使用 mockito 对插入方法进行单元测试

Posted

技术标签:

【中文标题】使用 mockito 对插入方法进行单元测试【英文标题】:unit test for insertion method using mockito 【发布时间】:2017-06-13 04:41:48 【问题描述】:

我在插入方法的单元测试中遇到了问题,虽然我使用的是模拟对象,但数据是插入到数据库中的,请问这是什么问题?

这里是方法的源代码

public void InsertPersonalData(PersonalData personaldata) throws SQLException, DAOException, ClassNotFoundException 
        try 
            PreparedStatement psmt = mysqlConnection.getPreparedStatement("INSERT INTO personal_data values(?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
            psmt.setString(1, personaldata.getiD());
            psmt.setString(2, personaldata.getPatientName());
            psmt.setString(3, personaldata.getBirthDate());
            psmt.setString(4, personaldata.getPlaceOfBirth());
            psmt.setString(5, personaldata.getGender());
            psmt.setString(6, personaldata.getNationality());
            psmt.setString(7, personaldata.getCurrentAddress());
            psmt.setString(8, personaldata.getCityAddress());
            psmt.setString(9, personaldata.getMaritalStatus());
            psmt.setString(10, personaldata.getOffspring());
            psmt.setString(11, personaldata.getAgeOfYoungestOffspring());
            psmt.setString(12, personaldata.getWorkNature());
            psmt.setString(13, personaldata.getPhoneNumber());
            psmt.setString(14, personaldata.geteMail());

            psmt.executeUpdate();

         catch (SQLException e) 
            throw new DAOException(e);

        

这是我使用模拟的方式

@RunWith(MockitoJUnitRunner.class)
public class PersonalDataDaoTest 

    public PersonalData newpd;

    @Mock
    Connection conn;

    @Mock
    PreparedStatement psmt;

    @InjectMocks
    PersonalDataDao newDAO = new PersonalDataDao();

测试代码:

@Test
    public void HappyTestForInsert() throws SQLException, DAOException, ClassNotFoundException 
        when(conn.prepareStatement(anyString())).thenReturn(psmt);
        //ArgumentCaptor<Integer> intcaptor = ArgumentCaptor.forClass(int.class);
        ArgumentCaptor<String> stringcaptor = ArgumentCaptor.forClass(String.class);
        String id = "11";
        String patientName = "yara";
        String birthDate = "2001-12-5";
        String placeOfBirth = "cairo";
        String gender = "female";
        String nationality = "egyptian";
        String currentAddress = "cairo";
        String cityAddress = "cairo";
        String maritalStatus = "married";
        String offspring = "1";
        String ageOfYoungestOffspring = "2";
        String workNature = "teacher";
        String phoneNumber = "0324324234";
        String eMail = "yara@hotmail.com";

        PersonalData p = new PersonalData(id, patientName, birthDate, placeOfBirth, gender, nationality, currentAddress, cityAddress, maritalStatus, offspring, ageOfYoungestOffspring, workNature, phoneNumber, eMail);
        newDAO.InsertPersonalData(p);
        //verify(psmt, times(1)).setInt(anyInt(), intcaptor.capture());
        verify(psmt, times(14)).setString(anyInt(), stringcaptor.capture());
        Assert.assertTrue(stringcaptor.getAllValues().get(0).equals(id));
        Assert.assertTrue(stringcaptor.getAllValues().get(1).equals(patientName));
        Assert.assertTrue(stringcaptor.getAllValues().get(2).equals(birthDate));
        Assert.assertTrue(stringcaptor.getAllValues().get(3).equals(placeOfBirth));
        Assert.assertTrue(stringcaptor.getAllValues().get(4).equals(gender));
        Assert.assertTrue(stringcaptor.getAllValues().get(5).equals(nationality));
        Assert.assertTrue(stringcaptor.getAllValues().get(6).equals(currentAddress));
        Assert.assertTrue(stringcaptor.getAllValues().get(7).equals(cityAddress));
        Assert.assertTrue(stringcaptor.getAllValues().get(8).equals(maritalStatus));
        Assert.assertTrue(stringcaptor.getAllValues().get(9).equals(offspring));
        Assert.assertTrue(stringcaptor.getAllValues().get(10).equals(ageOfYoungestOffspring));
        Assert.assertTrue(stringcaptor.getAllValues().get(11).equals(workNature));
        Assert.assertTrue(stringcaptor.getAllValues().get(12).equals(phoneNumber));
        Assert.assertTrue(stringcaptor.getAllValues().get(13).equals(eMail));

    

【问题讨论】:

请不要将代码段添加为图片,而是在您的帖子中包含实际代码。 我已经编辑过了 :) 插入发生在方法InsertPersonalData中。根据您的测试设置,您不是在模拟PersonalDataDAO,而是在对其进行测试,因此执行插入。 但是DAO类中的查询所以我使用了模拟,我该怎么办? 【参考方案1】:

您正在尝试验证准备好的语句在您的测试中的用法。您的代码设置方式不起作用,因为PreparedStatement 的实例是在您正在测试的方法中创建的:InsertPersonalData

但是您可以修改您的代码,使其变得可测试。第一步是将PreparedStatement 的创建移到一个单独的类中,然后可以在您的测试中模拟:

public class StatementProvider 
    public PreparedStatement createInsertStatementForPersonalData() 
        return PreparedStatement psmt = MysqlConnection.getPreparedStatement("INSERT INTO personal_data values(?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
    

接下来您更新您的PersonalDataDao 以使用StatementProvider

public class PersonalDataDao 
    private StatementProvider statementProvider;
    // Constructor and other methods ommitted
    public void InsertPersonalData(PersonalData personaldata) throws SQLException, DAOException, ClassNotFoundException 
        try 
            PreparedStatement psmt = statementProvider.createInsertStatementForPersonalData(); 
            psmt.setString(1, personaldata.getiD());
            psmt.setString(2, personaldata.getPatientName());
            psmt.setString(3, personaldata.getBirthDate());
            psmt.setString(4, personaldata.getPlaceOfBirth());
            psmt.setString(5, personaldata.getGender());
            psmt.setString(6, personaldata.getNationality());
            psmt.setString(7, personaldata.getCurrentAddress());
            psmt.setString(8, personaldata.getCityAddress());
            psmt.setString(9, personaldata.getMaritalStatus());
            psmt.setString(10, personaldata.getOffspring());
            psmt.setString(11, personaldata.getAgeOfYoungestOffspring());
            psmt.setString(12, personaldata.getWorkNature());
            psmt.setString(13, personaldata.getPhoneNumber());
            psmt.setString(14, personaldata.geteMail());

            psmt.executeUpdate();

         catch (SQLException e) 
            throw new DAOException(e);

        
     

然后你的测试看起来像这样:

@RunWith(MockitoJUnitRunner.class)
public class PersonalDataDaoTest 

    @Mock
    private PreparedStatement psmt;
    @Mock
    private StatmentProvider statementProvider; 

    @InjectMocks
    private PersonalDataDao newDAO; // This is the class under test
    @Test
    public void HappyTestForInsert() throws SQLException, DAOException, ClassNotFoundException 
        when(statementProvider.createInsertStatementForPersonalData()).thenReturn(psmt);
        //ArgumentCaptor<Integer> intcaptor = ArgumentCaptor.forClass(int.class);
        ArgumentCaptor<String> stringcaptor = ArgumentCaptor.forClass(String.class);
        String id = "11";
        String patientName = "yara";
        String birthDate = "2001-12-5";
        String placeOfBirth = "cairo";
        String gender = "female";
        String nationality = "egyptian";
        String currentAddress = "cairo";
        String cityAddress = "cairo";
        String maritalStatus = "married";
        String offspring = "1";
        String ageOfYoungestOffspring = "2";
        String workNature = "teacher";
        String phoneNumber = "0324324234";
        String eMail = "yara@hotmail.com";

        PersonalData p = new PersonalData(id, patientName, birthDate, placeOfBirth, gender, nationality, currentAddress, cityAddress, maritalStatus, offspring, ageOfYoungestOffspring, workNature, phoneNumber, eMail);
        newDAO.InsertPersonalData(p);
        //verify(psmt, times(1)).setInt(anyInt(), intcaptor.capture());
        verify(psmt, times(14)).setString(anyInt(), stringcaptor.capture());
        Assert.assertTrue(stringcaptor.getAllValues().get(0).equals(id));
        Assert.assertTrue(stringcaptor.getAllValues().get(1).equals(patientName));
        Assert.assertTrue(stringcaptor.getAllValues().get(2).equals(birthDate));
        Assert.assertTrue(stringcaptor.getAllValues().get(3).equals(placeOfBirth));
        Assert.assertTrue(stringcaptor.getAllValues().get(4).equals(gender));
        Assert.assertTrue(stringcaptor.getAllValues().get(5).equals(nationality));
        Assert.assertTrue(stringcaptor.getAllValues().get(6).equals(currentAddress));
        Assert.assertTrue(stringcaptor.getAllValues().get(7).equals(cityAddress));
        Assert.assertTrue(stringcaptor.getAllValues().get(8).equals(maritalStatus));
        Assert.assertTrue(stringcaptor.getAllValues().get(9).equals(offspring));
        Assert.assertTrue(stringcaptor.getAllValues().get(10).equals(ageOfYoungestOffspring));
        Assert.assertTrue(stringcaptor.getAllValues().get(11).equals(workNature));
        Assert.assertTrue(stringcaptor.getAllValues().get(12).equals(phoneNumber));
        Assert.assertTrue(stringcaptor.getAllValues().get(13).equals(eMail));

    

【讨论】:

是否可以在 StatementProvider 类中返回多个查询,因为我有多个类要以相同的方式进行测试? 当您在测试方法中模拟返回的模拟对象时,您可以有多个测试方法返回不同的模拟。我希望您对StatementProvider 的实现有几种方法,每种方法一种PrepraredStatement

以上是关于使用 mockito 对插入方法进行单元测试的主要内容,如果未能解决你的问题,请参考以下文章

使用 JUnit 和 Mockito 对 DAO 类进行单元测试

mockito在单元测试的使用一

学习笔记单元测试之mockito学习笔记

学习笔记单元测试之mockito学习笔记

学习笔记单元测试之mockito学习笔记

单元测试ContainerRequestFilter,它使用ResourceInfo和mockito