关于junit:单元测试(模拟)数据库,如何通过模拟验证数据库方法? 您所在的位置:网站首页 单元测试数据库数据 关于junit:单元测试(模拟)数据库,如何通过模拟验证数据库方法?

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

2024-06-13 22:54| 来源: 网络整理| 查看: 265

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

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

在我的代码中:

123456789101112@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); }

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

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

相关讨论 该代码似乎很奇怪。为什么有两个DBConnection对象?您正在"真实"实例上调用dropTable()。 DBConnection是否包含它委托的另一个DBConnection字段?如果没有,那么您的代码就没有意义,因为您创建了一个模拟DBConnection和一个真实的DBConnection。如果DBConnection中有一个DBConnection字段,则该字段将无效。提供一些DBConnection代码也许是个好主意。 是的,我有2个实例。一个是真实对象,另一个是模拟对象。 DBConnection类中没有成员类。 DBConnection类仅具有dropTable(),addEntry()之类的方法,并具有私有字段,这些私有字段是提供给DriverManager的主机,数据库和端口信息(基本JDBC连接) 好的,那真的可以解释,谢谢您的评论。我也期待这样的结果。但是,如何在不接触数据库的情况下测试我的数据库?有什么办法吗?唯一的解决方案是创建与开发数据库具有相同配置的测试数据库吗?我从您的评论中了解到,我需要驾驶真正的汽车以确保其正常工作吗? 一旦您的代码与另一个系统交互,就无法在没有另一个系统的情况下对其进行可靠的测试。这可以是数据库的副本版本或内存版本,但其他所有内容都不完整。也许有间接的测试方法,但是这些方法需要创建高度复杂的测试,实际上,该测试可能只会模拟国外系统的很大一部分。对于此类内容,存在集成测试,可以测试您的系统与其他系统的集成程度。

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

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

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

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

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

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

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

相关讨论 因此,这意味着,我不需要Mocking(其毫无意义)来测试实际的数据库连接器类是否有效。模拟只是为我们的输入提供"伪"的所谓输出。 由于要完全模拟它,需要您有效地模拟整个数据库,因此这并不是一个好计划。如果要在模拟所有依赖关系的情况下测试一个单元,则模拟非常好-例如,如果您有一个基于DB数据的服务,则可以模拟DBConnector并将模拟数据提供给该服务,因为您只想测试服务如何处理数据-确保DBConnector本身正常工作是另一个问题,应单独进行单元测试。 就像我需要从数据库查询用户名-密码集以在登录页面中使用它们。如果数据库尚未完成,我可以进行模拟并使用它来测试我的登录页面是否工作,而无需查询真正的页面(因为它尚不可用)。我使用嘲讽来不测试被选中的对象,以测试对象使用到的对象。 答对了。您可以单元(!)通过提供db相关对象的模拟,在db东西可以正常工作的前提下测试整个与登录相关的内容。实际的数据库内容将在其他地方进行(单元?)测试。当然,添加集成测试以将所有内容一起测试以查看它们是否全部组合也不错。 现在其水晶般清澈。

为什么不考虑在单元测试中使用内存数据库。也许使用DAO模式在内存和内存之间轻松切换。

保持实际的数据库交互层尽可能薄,以确保将逻辑抽象到单独的类中,这使测试变得更加容易,因为在这种情况下,您可以模拟数据库对象并专注于测试逻辑。

还要确定要测试的内容,最有可能要测试逻辑,而不是第三方数据库连接器的逻辑,因此将测试重点放在测试上。

如果需要此级别的测试,请考虑使用一组集成或系统测试来针对实际数据库测试应用程序功能,但是对于单元测试,内存中应该没问题。

通过将单元测试和集成测试结合起来,可以实现应用程序的总体置信度。

相关讨论 我向同事建议使用内存数据库,但我们同意在单元测试中使用测试数据库。尽管我在问题中提供了非DAO模式数据库建模,但我们使用DAO方法(对此我也不熟悉)。我不确定是否会影响我将使用的解决方案。我想我不了解模拟的目的,但现在我明白了。我不对整个测试过程负责(我希望),据我所知其他人将进行集成测试。

对于@Florian Schaetz的评论,我需要做这样的事情:

AuthenticatorApplicationInterface.java

1234public interface AuthenticatorInterface {         public boolean authenticateUser(String username, String password) throws EmptyCredentialsException; }

AuthenticatorApplication.java

1234567891011121314public class AuthenticatorApplication {     private AuthenticatorInterface authenticator;     public AuthenticatorApplication(AuthenticatorInterface authenticator)                           {             this.authenticator = authenticator;     }     public boolean authenticate(String username, String password) throws NotAuthenticatedException {        boolean authenticated;        authenticated = this.authenticator.authenticateUser(username, password);         return authenticated;         }     }

AuthenticatorApplicationTest.java

12345678910111213141516171819public class AuthenticatorApplicationTest {         @Test         public void testAuthenticate() throws EmptyCredentialsException {             AuthenticatorInterface authenticatorMock;             AuthenticatorApplication authenticator;             String username ="username";             String password ="noncorrectpassword";             authenticatorMock = Mockito.mock(AuthenticatorInterface.class);             authenticator = new AuthenticatorApplication(authenticatorMock);             when(authenticatorMock.authenticateUser(username, password)).thenReturn(false);             boolean actual = authenticator.authenticate(username, password);             assertFalse(actual);     } }



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有