我正在使用Spring Framework,Hibernate和JUnit。我正在测试UserEntity的持久性。

UserEntity具有以下关联:


ManyToMany-城市
ManyToMany-ActivityCategory

ManyToOne-UserType

@Test
public void testCreateNotExistingEmail() {
    UserTypeEntity userTypeEntity = userTypeDao.find(1L);

    BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(16);
    String password = encoder.encode("123456");

    List<CityEntity> cityEntities = new ArrayList<>();
    cityEntities.add(cityDao.find(1L));
    cityEntities.add(cityDao.find(2L));

    List<ActivityCategoryEntity> activityCategoryEntities = new ArrayList<>();
    activityCategoryEntities.add(activityCategoryDao.find(4L));
    activityCategoryEntities.add(activityCategoryDao.find(5L));

    UserEntity userEntity = new UserEntity();
    userEntity.setEmail("user@domain.com");
    userEntity.setIsActive(true);
    userEntity.setPassword(password);
    userEntity.setUserTypeEntity(userTypeEntity);
    userEntity.setCities(cityEntities);
    userEntity.setActivityCategories(activityCategoryEntities);

    userDao.create(userEntity);

    UserEntity userEntityCreated = userDao.find(userEntity.getId());

    Assert.assertNotNull(userEntityCreated);
    Assert.assertEquals(2, userEntityCreated.getCities().size());
    Assert.assertEquals(2, userEntityCreated.getActivityCategories().size());
}



我在测试中还能做得更好吗?

#1 楼

略作说明:您的测试名为testCreateNotExistingEmail@Test批注已经表明这是一个测试,因此不必在方法名本身中重复。

补充:我喜欢以[UnitOfWorkName]_[ScenarioUnderTest]_[ExpectedBehaviour]的格式构造测试。

当我查看代码时,很难说出测试的确切功能,因为方法名指示不存在的电子邮件的某些信息,这使我不得不考虑某个地方处理的异常。

但是,当我查看代码时,根本看不到任何断言。实际上,我只看到一封电子邮件在看似无关的上下文中使用过一次。

需要一些澄清:更好的方法名称。现在,当在大量测试中测试失败时,您可以在深入研究之前更精确地指出哪种情况出了问题。

评论


\ $ \ begingroup \ $
谢谢您的建议。我同意,该方法的名称可能会更好,但是您建议的名称确实很长。因此,我认为最好将信息放入Javadoc注释中。至少比“ TestCreationOfAUserWithEmail ...”具有更好的可读性,例如“使用电子邮件创建用户...”。
\ $ \ endgroup \ $
–user40964
2014年4月19日在18:09

\ $ \ begingroup \ $
如果第一个单词未经测试,则不管是否存在@Test批注,某些IDE(会想到IntelliJ)都不喜欢它。海事组织这对他们来说是个坏主意,但有时我们必须忍受自己拥有的东西
\ $ \ endgroup \ $
– Robert Snyder
2014年4月19日在18:09

\ $ \ begingroup \ $
为什么方法名称有多长会很重要?这是您永远不会称呼自己的事情。名称所要做的只是显示在您的测试结果窗口中,并尽可能地具有描述性,通过缩短它不会有任何好处。
\ $ \ endgroup \ $
– Jeroen Vannevel
2014年4月19日在18:11

\ $ \ begingroup \ $
@JeroenVannevel我明白你的意思。在这种情况下,最好使用更具描述性的名称。
\ $ \ endgroup \ $
–user40964
2014年4月19日在18:17

\ $ \ begingroup \ $
@Yoda:C#习惯,在Java中应该是小写。我的错
\ $ \ endgroup \ $
– Jeroen Vannevel
2014年4月19日在18:59

#2 楼

测试方法的名称是testCreateNotExistingEmail,但我不知道它与您要测试的内容有什么关系。

测试的目的是什么?如果没有其他用户实体具有相同的电子邮件,是否可以成功创建用户实体?如果是这样,那么我将改为执行以下操作:

@Test
public void testCreateNotExistingEmail() {
    UserEntity userEntity = new UserEntity();
    userEntity.setEmail("nonexistent@domain.com");
    userDao.create(userEntity);
}

@Test(expected=UniqueKeyIntegrityException.class)
public void testCannotCreateWithExistingEmail() {
    String email = "user@domain.com";

    // or something like this:
    Assert.assertNull(userDao.findByEmail(email));

    UserEntity userEntity = new UserEntity();
    userEntity.setEmail(email);
    userDao.create(userEntity);  // success

    userEntity.setEmail(email);
    userDao.create(userEntity);  // throws
}



是否需要为测试设置所有这些字段?如果不是,则忽略它们。例如,如果没有密码的用户有效,则在此测试用例中不要设置密码,因为这是不必要的。单元测试应尽可能地短。我将针对UserEntity本身的测试与验证正确的关系(与城市和类别)的测试分开。


您对关系(与城市和类别)的测试可能更多严格。最好在userEntityuserEntityCreated中比较每个城市和每个类别的ID。我将使用单独的测试方法:


一项针对城市关系的测试
一项针对类别关系的测试
为了增加安全性,我还要对City + category进行另一项测试。这可以简化,例如仅比较大小即可。


注意潜在的副作用。例如,如果您有多个使用userDao的测试,请确保在@Before中重新初始化,以使所有测试均以相同的设置开始,并且彼此之间没有副作用。

#3 楼

已经给出的答案是很好的答案,但我发现有些地方没有说。

第一:

您的测试确实包含一些数据库,可能是在生成时您在服务器上测试还是在开发数据库上。
您是否对@Transactional进行了类培训? br />为什么:

您将确保在方法结束时回滚您的数据库。
这意味着将数据库设置为与方法开始时一样的原始状态。
测试的执行顺序可能会有所变化,因此可能导致先前/进一步的测试失败。

第二个:

为什么在失败时不提供带有断言的文本消息,如下所示:消息,因此您可以直接知道断言在您的方法中失败了。

希望可以为您提供进一步的帮助。

评论


\ $ \ begingroup \ $
好点。所有测试均继承自TestDaoSetup类,该类具有ContextConfiguration(...这里的配置位置...),TransactionConfiguration和Transactional批注。我喜欢你的第二点。我会肯定使用它。不幸的是,我无法将更多答案标记为正确,他们应该将其真正添加到此站点。
\ $ \ endgroup \ $
–user40964
14年4月19日在19:13

\ $ \ begingroup \ $
不必这样做,我们在这里可以互相帮助;)
\ $ \ endgroup \ $
– chillworld
14年4月19日在19:18