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

Posted

技术标签:

【中文标题】使用 JUnit 和 Mockito 对 DAO 类进行单元测试【英文标题】:Unit testing of DAO classes using JUnit and Mockito 【发布时间】:2020-01-17 17:40:43 【问题描述】:

我有 DaoImpl 类:

public class MessageTypeDaoImpl implements MessageTypeDao

    public int[] createMessageTypes(final List<MessageType> messageTypes)
        String sql = "INSERT INTO MSG_TYPE VALUES(?, ?)";
        return jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() 
            public void setValues(PreparedStatement ps, int i) throws SQLException 
                MessageType messageType = messageTypes.get(i);
                ps.setString(1, messageType.getMessageId());
                ps.setString(2, messageType.getMessageName());
            

            public int getBatchSize()
                return messageTypes.size();
            
    );

我的测试:

@RunWith(MockitoJUnitRunner.class)
public class MessageTypeDaoImplTest 

@Mock
private JdbcTemplate jdbcTemplate;

@Spy
@InjectMocks
MessageTypeDaoImpl messageTypeDaoImpl;
@Before
public void setUp()
    MockitoAnnotations.initMocks(this);

@Test
public void createMessageTypes() 
    int[] returnCount = new int[1];
    List<MessageType> messageTypeList = new ArrayList<MessageType>();
    messageTypeList.add(getSampleMessageType());
    messageTypeDaoImpl.createMessageTypes(messageTypeList);
    doReturn(returnCount).when(messageTypeDaoImpl).createMessageTypes(messageTypeList);
    assertEquals(returnCount, messageTypeDaoImpl.createMessageTypes(messageTypeList));



public MessageType getSampleMessageType()
    return new MessageType("messageTypeId", "messageTypeName");

测试成功,但是当我运行 junit 覆盖测试时,它显示 public void setValues() 方法没有被覆盖,因此我的整体单元测试行覆盖率低于要求。我们可以涵盖那部分吗?如果是,那么我们如何做到这一点?谢谢。

【问题讨论】:

不要模拟 JdbcTemplate,使用真实的实例。您的 Spring 容器中可能已经有一个真实的实例。请注意,JdbcTemplate 具有依赖关系,例如:DataSource。您可能需要模拟 DataSource 并将其注入 JdbcTemplate。您可以让 Spring 为您注入 if:在您的单元测试中有一个 DataSource 类型的成员变量,并在其上使用 @MockBean 注释。 在 doReturn().when() 语句之前调用 `messageTypeDaoImpl.createMessageTypes(messageTypeList);` 有什么意义?还有:你为什么在这里使用间谍?似乎您正在将 Mockito 的各种元素拼凑在一起,却不知道它们的实际用途是什么? @GhostCat 我调用了 createMessageTypes,因为如果我不这样做,该方法将不会被调用,并且不会有代码覆盖。我需要确保我的代码覆盖率尽可能高(IntelliJ IDE 中的类 % 和行 % 覆盖率)。关于 Spy 注释,我在调用方法时遇到了问题(再次用于代码覆盖),*** 上有人说我们可以使实例接近真实实例(或半模拟)并调用该方法。我之前没有做过那么多的单元测试,更不用说mockito了。所以我想了解如何让它协同工作。 【参考方案1】:

试试下面的代码spinet。我也会介绍代码。我从头到尾检查了它,它起作用了。

int[] batchInsert=new int[] 1,2;
        try 

            Mockito.doAnswer(invocationOnMock -> 

                PreparedStatement ps = Mockito.mock(PreparedStatement.class);
                BatchPreparedStatementSetter psr = invocationOnMock.getArgument(1);
                psr.setValues(ps, 1);
                return batchInsert;

            ).when(jdbcTemplate).batchUpdate(anyString(),  Mockito.any(BatchPreparedStatementSetter.class));

【讨论】:

以上是关于使用 JUnit 和 Mockito 对 DAO 类进行单元测试的主要内容,如果未能解决你的问题,请参考以下文章

JUnit 在带有 @Autowired 注释的 Spring Boot 中不起作用

如何使用 mockito 和 junit 测试此功能?

如何在 JUnit5 中使用 Mockito

使用 Junit 和 Mockito 嵌套异常问题测试 POST Api

如何使用 Mockito 和 JUnit 在 Spring Boot 中测试 POST 方法

如何使用mockito和junit为Java中的ExecutorService编写测试用例?