对单元测试 DAO 的怀疑

Posted

技术标签:

【中文标题】对单元测试 DAO 的怀疑【英文标题】:doubts about unit testing DAOs 【发布时间】:2015-10-07 03:17:36 【问题描述】:

我正在寻找为典型 DAO 方法构建单元测试的信息(通过用户名等查找用户),我发现了几个使用类似这样的模拟的示例:http://www.christophbrill.de/de_DE/unit-testing-with-junit-and-mockito/

@Test
public void testComeGetSome() 
    // Mock the EntityManager to return our dummy element
    Some dummy = new Some();
    EntityManager em = Mockito.mock(EntityManager.class);
    Mockito.when(em.find(Some.class, 1234)).thenReturn(dummy);

    // Mock the SomeDao to use our EntityManager
    SomeDao someDao = Mockito.mock(SomeDao.class);
    Mockito.when(someDao.comeGetSome(1234)).thenCallRealMethod();
    Mockito.when(someDao.getEntityManager()).thenReturn(em);

    // Perform the actual test
    Assert.assertSame(dummy, someDao.comeGetSome(1234));
    Assert.assertNull(someDao.comeGetSome(4321));

Lasse Koskela 的书中也有类似的,使用 EasyMock 代替 Mockito。

问题是:我们在这些示例中真正测试的是什么?我们基本上是通过模拟告诉查询应该返回什么对象,然后断言实际上它返回了我们告诉它返回的对象。

我们不会测试查询是否正确,或者它是否返回不同的对象或根本没有对象(甚至多个对象)。当对象在数据库中不存在时,我们无法测试它是否返回 null。这一行

Assert.assertNull(someDao.comeGetSome(4321));

有效是因为该参数没有脚本交互,而不是因为对象不存在。

看起来我们只是在测试该方法是否调用了正确的方法和对象(em.find)。

对此进行单元测试有什么意义? Java 中有没有好的框架可以快速建立内存数据库并使用它执行测试?

【问题讨论】:

似乎是星期五的忧郁。模型用于返回特定查询的特定值。仅仅这样进行测试当然是荒谬的。但是,随后将可以测试使用 DAO 查询的业务逻辑。 将每只数过的羊都用棍子棒打,提醒我数羊不两次。 这是我一直关心的话题,一般办公室里都会有人来告诉我“我们需要写Junit测试”,我总是回复“你想测试什么”,人们普遍对 db 层和 application 层的单元测试感到困惑,所以,我主要为 application 层和来自 DB 的模拟数据编写代码,但如果你真的想用内存 db 编写 DAO 测试用例,那么我建议使用 H2 (h2database.com) 或 HyperSQL (hsqldb.org) 你在做什么,不过是一派胡言。如果要测试 DAO 层,请执行集成测试。你永远不会模拟即将被测试的方法行为。 那么,如果我理解您的 cmets,您同意我的看法,并且这些方法通常存在于会话外观、服务外观、DAO 或您所称的任何东西中,不应该进行单元测试。据我了解,使用数据库的快速副本进行集成测试... 【参考方案1】:

你的怀疑是有道理的。其实大多数情况下不需要用单元测试来测试DAO,因为单元测试只处理一层,而DAO与数据库层配合。

这篇文章解释了这个想法: http://www.petrikainulainen.net/programming/testing/writing-tests-for-data-access-code-unit-tests-are-waste/

因此我们应该使用集成测试来测试 DAO 和数据库层。 集成测试同时考虑 DAO 和数据库层。

本文将为您提供 Spring + Hibernate 示例: https://dzone.com/articles/easy-integration-testing

【讨论】:

【参考方案2】:

它看起来更像是服务测试,而不是真正的 DAO 测试。 例如,我使用dbunit 来测试我的 DAO 层。

例如,我有 Author 表有 2 个字段:idname。 我正在创建一个数据集 xml 文件,例如

<?xml version="1.0" encoding="UTF-8"?>
<dataset>
    <AUTHOR AUTHOR_ID="1" NAME="FirstAuthor"/>
    ...
    <AUTHOR AUTHOR_ID="10" NAME="TenthAuthor"/>
</dataset>

然后在我的测试类中使用 Mockito 我正在测试我的 DAO 方法,例如

@Test
@DatabaseSetup(value = "/dao/author/author-data.xml")
public void testFindAll() 
    List<Author> authorList = this.authorDAO.findAll();
    assertEquals(10, authorList.size());

【讨论】:

这样做的目的是什么?,测试用例没有给出那么多价值,看问题的cmets。 我猜想 xml 数据集应该模仿真实的数据库,所以我们正在测试的同一个查询应该适用于两者。

以上是关于对单元测试 DAO 的怀疑的主要内容,如果未能解决你的问题,请参考以下文章

尝试对 DAO 类进行单元测试时,SessionFactory 没有自动装配

如何使用 Spring Security 对 Spring 4 DAO 方法进行单元测试?

对使用 Spring JDBC 的 DAO 类进行单元测试

DAO的单元测试

使用 H2 数据库对 DAO 层进行单元测试

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