17

How does one go about unit testing an object that can't be instantiated? Because currently I have a method that converts a ResultSet to an object but I'm unsure if this violates any programming principles.

public CItem convert(ResultSet rs) {
    CItem ci = new CItem ();

    try {
        ci.setHinumber(rs.getString("id"));
        ci.setHostname(rs.getString("sysname"));
        ci.setOs(rs.getString("zos"));
        ci.setTenant(rs.getString("customer_name"));
        //ci.setInstallation(rs.getField("installation_name"));
    } catch (SQLException e) {
        e.printStackTrace();
    }
    return ci;
}

Do I need to look for a different way to approach this solely because it can't be unit tested? Or can I somehow fake a ResultSet object.

Any help would be appreciated.

DGK
  • 2,947
  • 5
  • 32
  • 47

2 Answers2

26

You could simply mock your ResultSet to provide a value for each field and check that the result contains what you expect.

For example with Mockito, your test would be something like this:

@RunWith(MockitoJUnitRunner.class)
public class SomeClassTest {

    @Mock
    private ResultSet resultSet;

    @Test
    public void testConvert() throws SQLException {
        // Define the behavior of the mock for each getString method's call
        Mockito.when(resultSet.getString("id")).thenReturn("myId");
        Mockito.when(resultSet.getString("sysname")).thenReturn("myHost");
        Mockito.when(resultSet.getString("zos")).thenReturn("myOS");
        Mockito.when(resultSet.getString("customer_name")).thenReturn("myCustomerName");

        // Launch the method against your mock
        SomeClass someClass = new SomeClass();
        CItem item = someClass.convert(resultSet);

        // Check the result
        Assert.assertNotNull(item);
        Assert.assertEquals("myId", item.getHinumber());
        Assert.assertEquals("myHost", item.getHostname());
        Assert.assertEquals("myOS", item.getOs());
        Assert.assertEquals("myCustomerName", item.getTenant());
    }
}
Nicolas Filotto
  • 43,537
  • 11
  • 94
  • 122
1

If your class does not deal with DB access, accepting a ResultSet as an argument feels like a code smell.

You can use a mocking framework like Mockito or Power Mock to create a mock ResultSet. However you should not mock such classes which you did not write (i.e. libraries/ JDK classes).

Suppose that your ResultSet represents some order data from an Order table. What this method really needs is 'order data' and you should not worry about how and where you get this data from at this point. So you should ideally define an interface like this.

interface OrderRepository {
    OrderData get();
}

Then you can have a class which implements this interface JDBCOrderRepository which deals with ResultSet. And your method ('convert') will now accept an OrderRepository instead of ResultSet. In order to test your method you mock OrderRepository instead of ResultSet which is easier.

Now how would you test JDBCOrderRepository? Well, probably you should test it with a running instance of DB which is in fact an integration test.

Fahim Farook
  • 1,482
  • 2
  • 14
  • 38