【问题标题】:Doesn't receive an error in java test在 java 测试中没有收到错误
【发布时间】:2015-04-03 08:12:40
【问题描述】:

我的测试不应该通过。我应该在第 2 行收到一个错误,因为我在第 1 行输入了错误的值new Long(0)。 请告诉我我的错误在哪里。 谢谢。

    @Test
    public void getPersonListByOtdelIdTest() {            
        Long otdelId = new Long(454);
        ArgumentCaptor<Long> argumentOtdelId = ArgumentCaptor.forClass(Long.class);
        SessionFactory mockedSessionFactory = mock(SessionFactory.class);
        Session session = mock(Session.class);
        Query query = mock(Query.class);
        PersonDAOImpl personDAO = new PersonDAOImpl(mockedSessionFactory);
        when(mockedSessionFactory.getCurrentSession()). thenReturn(session);
        when(session.createQuery("FROM Person P where P.otdel.otdelId = :otdelId")).thenReturn(query);
 #1-->  when(query.setParameter("otdelId", new Long(0))).thenReturn(query);
        when(query.list()).thenReturn(persons);

        List<Person> expectedPersons =  personDAO.getPersonListByOtdelId(otdelId);

        verify(mockedSessionFactory).getCurrentSession();
        verify(session).createQuery("FROM Person P where P.otdel.otdelId = :otdelId");
        verify(query).setParameter(eq("otdelId"), argumentOtdelId.capture());
        verify(query).list();
 #2-->  assertEquals(otdelId, argumentOtdelId.getValue());
        assertTrue(expectedPersons.containsAll(persons));
    }

 public class PersonDAOImpl implements PersonDAO {
    public List<Person> getPersonListByOtdelId(Long otdelId) {
        Query query = sessionFactory.getCurrentSession().createQuery("FROM Person P where P.otdel.otdelId = :otdelId");
        query.setParameter("otdelId", otdelId);
        List<Person> listPersons = query.list();
        return listPersons;
    } 
 }

【问题讨论】:

  • 你正在开发什么样的模拟 API?

标签: java testing junit mocking mockito


【解决方案1】:

我不明白为什么您会期望 #2 的断言失败。您的测试通过454(作为Long)进入getPersonListByOtdelId(),因此将传递给query.setParameter()。 #1 中的when() 代码本质上是无操作的,因为没有使用这些值调用query.setParameter(),但是如果when() 中指定的调用从未发生过,Mockito 不会抱怨,并且下面的代码test 不检查返回值,所以也不例外。

在任何情况下,您都不需要ArgumentCaptor;您只需要让 Mockito 验证是否将正确的值传递给 setParameter()

事实上,很多验证调用是不需要的,你可以这样做:

@Test
public void getPersonListByOtdelIdTest() {
  Long otdelId = 454L; // or = Long.valueOf(454); don't use new Long
  SessionFactory mockedSessionFactory = mock(SessionFactory.class);
  Session session = mock(Session.class);
  Query query = mock(Query.class);

  when(mockedSessionFactory.getCurrentSession()).thenReturn(session);
  when(session.createQuery("FROM Person P where P.otdel.otdelId = :otdelId"))
      .thenReturn(query);
  when(query.setParameter("otdelId", otdelId)).thenReturn(query);
  when(query.list()).thenReturn(persons);

  PersonDAOImpl personDAO = new PersonDAOImpl(mockedSessionFactory);
  List<Person> result = personDAO.getPersonListByOtdelId(otdelId);

  verify(query).setParameter("otdelId", otdelId);
  assertEquals(result, persons);
}

您无需验证是否调用了getCurrentSession(),因为如果不是,被测代码将无法获得会话。您无需验证是否将正确的查询传递给createQuery(),因为被测代码使用了不同的查询,Mockito 不会返回模拟查询(当然,除非您使用RETURNS_MOCKS)。

话虽如此,我认为上述测试不是一个好的测试。测试几乎完全反映了代码,它并没有验证代码是否可以工作。换句话说,它是change detector test

我不会使用模拟框架来测试PersonDaoImpl。相反,我会编写一个启动内存数据库的测试,使用的模式文件也用于在生产中创建实际表。

我会使用模拟来测试依赖于PersonDAO 的类。

【讨论】:

  • 模拟框架不适合DAO类,所以当我们必须为类编写单元测试时我们应该怎么做?
  • @TienNguyen 正如我所说,如果我正在为 DAO 类编写测试测试,我会让测试创建一个内存数据库,并让 DAO 与测试创建的数据库进行交互。这是让我相信 DAO 类有效的最起码的事情。在上面的示例测试中,如果列的名称是odtelId,但代码和测试使用了otdelId,那么测试会通过,但该类会在生产中抛出异常。
  • @NamshubWriter 非常感谢您的详细解释。据我了解,我应该在服务和控制器级别使用模拟测试。是不是一个dao级别测试的好例子:link
  • @zigfridus accepted answer 对我来说似乎是一个很好的 DAO 测试。我将添加一个 @Before 方法,该方法使用原始 SQL 插入一些示例数据。
  • 好的,再次感谢您。我会根据你的建议改变我的 dao 测试。
猜你喜欢
  • 2022-08-24
  • 1970-01-01
  • 1970-01-01
  • 2013-06-20
  • 1970-01-01
  • 2016-05-27
  • 2020-06-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多