单元测试(模拟)数据库,如何通过模拟验证数据库方法?

Mel*_*lih 2 tdd junit unit-testing mocking mockito

由于以前没有进行单元测试和模拟的经验,因此我跟随Mockito进行了有关JUnit的初学者教程,并进行了一些练习。

现在,我需要对一些类方法进行单元测试,这些方法在MySQL数据库上执行基本的数据库操作。我不想对数据库进行真正的更改。

在我的代码中:

@InjectMocks private DBConnection dbConnection;
@Mock private DBConnection mockDBConnection;

@Test
public void testDropTable() {

    Mockito.when(mockDBConnection.dropTable()).thenReturn(0);

    // dropTable() returns 0 if table dropped
    int result = dbConnection.dropTable();
    Assert.assertEquals(result, 0);
}
Run Code Online (Sandbox Code Playgroud)

为了验证(使用assertEquals())测试结果,我正在调用真正的dropTable()方法,并且它确实删除了表(实际上是显而易见的,因为我正在调用真正的DBConnection实例)

无论如何,是否可以在不访问真实数据库的情况下验证类似方法?还是我误解了单元测试和模拟的概念?

Flo*_*etz 5

想象一下……您有两辆车,一辆是真车,另一辆是假车。现在,您进入真正的汽车,然后开车。你为什么期望不动呢?您对假冒的汽车没有做任何事情,因此即使您告诉它“如果我开始驾驶也不要移动”,这也不会改变当您下车时真正的汽车会移动的事实。

同样在这里,您创建了一个伪造的DBConnection和一个真实的DBConnection。真正的人会做任何事情。可以将伪造的东西配置为执行其他操作,就像使用Mockito.when(...)一样。但这并不会改变真正的行为。

您的测试实际上是没有意义的,因为您在这里的唯一选择是摆脱模拟,因为它没有任何有意义的目的。您不测试模拟。做什么的?这就像制造一辆假车并对其进行测试-它不会告诉您任何有关真车的信息。如果您在该测试中要求它执行X操作,则无需测试该假车即可知道它会执行X操作。

有两种方法可以测试DBConnection类:

a)您可以将其连接到数据库并检查其是否可以正常工作。当然,这将不再是单元测试,而是集成测试。在某些情况下,您可以使用内存数据库(例如HSQLDB)来加快此测试的速度。但是,至少到最后,您可以合理地确定您的代码已实现了预期的功能。

b)IF和只有IF DBConnection内部有一些对象与数据库进行实际对话,您可以模拟这些对象,然后测试DBConnection。当然,这只会将您的问题转移到另一层,因为这样您就不确定那些对象是否起作用-如果这些对象起作用,您只会知道DBConnection起作用。虽然这是一个很好的认识,但是它并不能回答您的数据库代码最后是否可以工作的问题。

最后,您只能通过连接到数据库来完全测试数据库连接。其他所有内容都不是完整的测试。

  • 由于完全模拟它需要您有效地模拟整个数据库,所以这并不是一个好计划。如果要在模拟所有依赖关系的情况下测试一个单元,则模拟非常好-例如,如果您有一个基于DB数据的服务,则可以模拟DBConnector并将模拟数据提供给该服务,因为您只想测试服务如何处理数据-确保DBConnector本身正常工作是另一个问题,应单独进行单元测试。 (2认同)