user3417078
user3417078

Reputation: 265

How to mock a single statement in java

I want to implement a database reader using Spring and JDBC.

@Component
public class MyReader() {

    public void read() {
        /* Other code */

        ResultSet rs = stmt.executeQuery(sql);
        while(rs.next()){
            String myDbValue = rs.getString("myColumn");
        }

        /* Other code */
    }
}

I want to test the behavior of my class, if column myColumn isn't present.

One solution would be to move the constant myColumn to a private method, but some guys on SO told other users, that mocking private methods smells, see Raedwalds comment and I would agree. I could also mock the database file itself, but mocking files isn't a good way too.

Any ideas how handle this issue?

Upvotes: 1

Views: 2203

Answers (1)

nbrooks
nbrooks

Reputation: 18233

Your test code, and therefore what/how you choose to mock, is intrinsically and inextricably linked to the functionality of the method you're testing. Now, this doesn't mean that it should be tied to the implementation of that method (you want to keep this fairly decoupled), but the core purpose of what the method aims to do is what you should be testing. This is why well-designed, well thought out tests drives good API design.

The question you therefore need to ask yourself is What is the read method doing?.

I suspect that both the Statement and the ResultSet returned from executing the query are implementation details that you can mock out for the purposes of your test.

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import static org.mockito.Matchers.*;

import java.sql.*;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class MyReaderTest {

    @InjectMocks
    private MyReader myReader;

    @SuppressWarnings("unchecked")
    @Before
    public void setUp() throws Exception {
        Statement s = mock(Statement.class);
        ResultSet rs = mock(ResultSet.class);

        when(s.executeQuery(anyString())).thenReturn(rs);
        when(rs.getString("myColumn")).thenThrow(SQLException.class);
    }

    @Test
    public void testRead_AccessNonExistentColumn() {
        // Use mock statement and mock resultset
    }

}

Upvotes: 3

Related Questions