找到你要的答案

Q:Using Mockito and PowerMockito for DAO testing

Q:使用DAO测试mockito和powermockito

I want to test my DAO methods using Mockito (and PowerMockito if needed), but I don't know how to do this. The biggest problem with calling static method (MySQLDAOFactory.getConnection() in MySQLStationDAO). Can you help me?

I obtain connection this way:

public class MySQLDAOFactory extends DAOFactory {     
        public static Connection getConnection() throws DAOException {
            Connection con = null;
            try {
                con = getDataSource().getConnection();
            } catch (SQLException e) {
                throw new DAOException(Messages.CANNOT_OBTAIN_CONNECTION, e);
            }
            return con;
        }

And here is a DAO method:

public class MySQLStationDAO implements StationDAO {
    @Override
    public List<Station> getAllStations() throws DAOException {
        List<Station> stations = new ArrayList<>();
        Connection con = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            con = MySQLDAOFactory.getConnection();
            stmt = con.createStatement();
            rs = stmt.executeQuery(MySQLQueries.SQL_GET_ALL_STATIONS);
            while (rs.next()) {
                stations.add(extractStation(rs));
            }
        } catch (SQLException e) {
            throw new DAOException(Messages.CANNOT_OBTAIN_ALL_STATIONS, e);
        } finally {
            MySQLDAOFactory.close(con, stmt, rs);
        }
        return stations;
    }

我想测试我的DAO方法采用mockito(PowerMockito如果需要的话),但我不知道该怎么做。调用静态方法最大的问题(mysqldaofactory。getconnection()在mysqlstationdao)。你能帮我吗?

我得到这样的连接:

public class MySQLDAOFactory extends DAOFactory {     
        public static Connection getConnection() throws DAOException {
            Connection con = null;
            try {
                con = getDataSource().getConnection();
            } catch (SQLException e) {
                throw new DAOException(Messages.CANNOT_OBTAIN_CONNECTION, e);
            }
            return con;
        }

这里是一个DAO方法:

public class MySQLStationDAO implements StationDAO {
    @Override
    public List<Station> getAllStations() throws DAOException {
        List<Station> stations = new ArrayList<>();
        Connection con = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            con = MySQLDAOFactory.getConnection();
            stmt = con.createStatement();
            rs = stmt.executeQuery(MySQLQueries.SQL_GET_ALL_STATIONS);
            while (rs.next()) {
                stations.add(extractStation(rs));
            }
        } catch (SQLException e) {
            throw new DAOException(Messages.CANNOT_OBTAIN_ALL_STATIONS, e);
        } finally {
            MySQLDAOFactory.close(con, stmt, rs);
        }
        return stations;
    }
answer1: 回答1:
  1. JUnit: use @RunWith(PowerMockRunner.class) at the class-level.

    TestNG: make your test class extend PowerMockTestCase.

  2. Use @PrepareForTest(MySQLDAOFactory.class) at the class-level in order to instruct PowerMock to prepare the MySQLDAOFactory class for testing.

  3. Use PowerMockito.mockStatic(MySQLDAOFactory.class) in order to mock all methods of MySQLDAOFactory class.

    It is also possible to use partial mocking:

    PowerMockito.stub(PowerMockito.method(MySQLDAOFactory.class, "getConnection")).toReturn(Mockito.mock(Connection.class));

  4. Use something similar in order to stub getConnection():

    Connection mockConnection = Mockito.mock(Connection.class); Mockito.when(MySQLDAOFactory.getConnection()).thenReturn(mockConnection);

  5. Execute getAllStations() on a real instance of MySQLStationDAO, since you are testing MySQLStationDAO class.

  6. If you want to verify that getConnection() method has been called, use something similar:

    PowerMockito.verifyStatic(); MySQLDAOFactory.getConnection();

    However, please read Mockito.verify(T) javadoc for the reasons why it is recommended either to stub or to verify the invocation, not both.

In general, you may want to consult Mockito docs and PowerMockito docs for more information.

Full example that was created using JUnit 4.11, Mockito 1.9.5 and PowerMock (PowerMockito) 1.5.6 (please be careful with versions, since there is a lot of compatibility issues):

@RunWith(PowerMockRunner.class)
@PrepareForTest(MySQLDAOFactory.class)
public class MySQLDAOFactoryTest {

    private StationDAO stationDAO;

    @Mock
    private Connection mockConnection;

    @Mock
    private Statement mockStatement;

    @Mock
    private ResultSet mockResultSet;

    @Before
    public void setUp() {
        stationDAO = new MySQLStationDAO();
    }

    @Test
    public void testGetAllStations_StatementCreated() throws DAOException, SQLException {
        // given
        PowerMockito.mockStatic(MySQLDAOFactory.class);
        Mockito.when(MySQLDAOFactory.getConnection()).thenReturn(mockConnection);
        Mockito.when(mockConnection.createStatement()).thenReturn(mockStatement);
        Mockito.when(mockStatement.executeQuery(anyString())).thenReturn(mockResultSet);

        // when
        stationDAO.getAllStations();

        // then
        Mockito.verify(mockConnection).createStatement();
    }
}

What is next? Check that executeQuery() method has been called with expected arguments? Test how SQLException is handled? These are reasonable scenarios for unit testing, but what about integration testing? I would recommend DBUnit for this purpose. It puts your test database into a known state between test runs, and allows to verify a returned result against an expected XML dataset.

  1. 使用JUnit:@若(PowerMockRunner类)在类级别。

    测试:让你的测试类扩展PowerMockTestCase。

  2. 使用“preparefortest(mysqldaofactory。类)以班级指导powermock准备测试mysqldaofactory类。

  3. Use PowerMockito.mockStatic(MySQLDAOFactory.class) in order to mock all methods of MySQLDAOFactory class.

    也可以使用部分嘲弄:

    PowerMockito。存根(PowerMockito。法(MySQLDAOFactory.class,“调用”)),toReturn(mockito。模拟(连接。类));

  4. 以类似于短getconnection():

    Connection mockConnection = Mockito.mock(Connection.class); Mockito.when(MySQLDAOFactory.getConnection()).thenReturn(mockConnection);

  5. 在mysqlstationdao实例执行getallstations(),既然你是测试mysqlstationdao类。

  6. 如果你想验证getconnection()方法被调用,使用类似的东西:

    PowerMockito.verifyStatic(); MySQLDAOFactory.getConnection();

    然而,请阅读Mockito。验证(T)的javadoc的原因,建议要么存根或验证调用,不。

在一般情况下,你可能想咨询mockito医生和PowerMockito医生的更多信息。

完整的例子,使用JUnit 4.11创建的,mockito 1.8.5和powermock(powermockito)1.5.6(请注意版本,因为有很多兼容性问题):

@RunWith(PowerMockRunner.class)
@PrepareForTest(MySQLDAOFactory.class)
public class MySQLDAOFactoryTest {

    private StationDAO stationDAO;

    @Mock
    private Connection mockConnection;

    @Mock
    private Statement mockStatement;

    @Mock
    private ResultSet mockResultSet;

    @Before
    public void setUp() {
        stationDAO = new MySQLStationDAO();
    }

    @Test
    public void testGetAllStations_StatementCreated() throws DAOException, SQLException {
        // given
        PowerMockito.mockStatic(MySQLDAOFactory.class);
        Mockito.when(MySQLDAOFactory.getConnection()).thenReturn(mockConnection);
        Mockito.when(mockConnection.createStatement()).thenReturn(mockStatement);
        Mockito.when(mockStatement.executeQuery(anyString())).thenReturn(mockResultSet);

        // when
        stationDAO.getAllStations();

        // then
        Mockito.verify(mockConnection).createStatement();
    }
}

下一步是什么?检查executequery()方法被称为预期的争论?测试异常处理?这些是单元测试的合理方案,但是集成测试呢?我想推荐DBUnit为这个目的。它将测试数据库置于测试运行之间的已知状态,并允许对预期的xml数据集验证返回的结果。

answer2: 回答2:

As you say, your problem is when you are calling MySQLDAOFactory.getConnection(); In terms of testing you want to test your MySQLStationDAO class. This is your SUT (system under test). That means that you have to mock all the dependencies that your SUT has. In this case, the MySQLDAOFactory.

To do that you can use Mockito to easily mock that class and stub the methods that MySQLDAOFactory presents. One example would be

    package com.iseji.app.dao;

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

import java.sql.Connection;

import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class TestMySqlDaoFactory {

    MySqlDaoFactory mySqlDaoFactory;
    Connection connection;

    @Before
    public void setUp() throws DAOException {
        mySqlDaoFactory = mock(MySqlDaoFactory.class);
        connection = mock(Connection.class);
    }

    @Test(expected = DAOException.class)
    public void testEmptyUrlGetsDaoException() throws DAOException {
        when(mySqlDaoFactory.getConnection(null)).thenThrow(new DAOException());
        mySqlDaoFactory.getConnection(null);
    }

    @Test
    public void testFullUrlGetsConnection() throws DAOException {
        when(mySqlDaoFactory.getConnection(anyString())).thenReturn(connection);
        Assert.assertEquals(mySqlDaoFactory.getConnection(anyString()), connection);
    }
}

As you can see you can specify the behaviour of you DaoFactory. That isolates your Dao class which is the class that you want to test.

就像你说的,你的问题是当你打电话mysqldaofactory。getconnection();在测试你想测试你的mysqlstationdao类。这是你的系统(系统测试)。这意味着你必须模仿你的SUT有依赖。在这种情况下,该mysqldaofactory。

这样做,你可以使用mockito轻松模拟类和存根的方法,mysqldaofactory介绍。一个例子是

    package com.iseji.app.dao;

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

import java.sql.Connection;

import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class TestMySqlDaoFactory {

    MySqlDaoFactory mySqlDaoFactory;
    Connection connection;

    @Before
    public void setUp() throws DAOException {
        mySqlDaoFactory = mock(MySqlDaoFactory.class);
        connection = mock(Connection.class);
    }

    @Test(expected = DAOException.class)
    public void testEmptyUrlGetsDaoException() throws DAOException {
        when(mySqlDaoFactory.getConnection(null)).thenThrow(new DAOException());
        mySqlDaoFactory.getConnection(null);
    }

    @Test
    public void testFullUrlGetsConnection() throws DAOException {
        when(mySqlDaoFactory.getConnection(anyString())).thenReturn(connection);
        Assert.assertEquals(mySqlDaoFactory.getConnection(anyString()), connection);
    }
}

正如你可以看到,你可以指定行为你DaoFactory。隔离你的DAO类,这是你想测试的类。

java  mockito  dao  powermockito