unit-testing - JUnit 避免重复断言
问题描述
我正在编写将实体转换为 DTO 的简单测试用例,反之亦然。问题更多是关于设计。在下面的代码中留下重复项是否可以接受,或者为这个断言创建外部方法更好?由于我是 Java 新手,有人可以给我提示一下吗?任何通用方法?我不想为这种简单的实体及其 DTO 使用继承或任何其他抽象,因为将有更多的代码,而不仅仅是几行重复的代码。这是它现在的样子:
@Test
void addressToAddressDTO() {
Address address = getAddress();
AddressDTO addressDTO = addressMapper.addressToAddressDTO(address);
assertAll("Check if values were properly bound",
() -> {
assertEquals(address.getCity(), addressDTO.getCity());
assertEquals(address.getUserDetails().getFirstName(), addressDTO.getUserDetails().getFirstName());
assertEquals(address.getUserDetails().getUser().getUsername(), addressDTO.getUserDetails().getUser().getUsername());
assertEquals(address.getUserDetails().getContact().getEmail(), addressDTO.getUserDetails().getContact().getEmail());
assertEquals(address.getUserDetails().getProfileImage().getImageUrl(), addressDTO.getUserDetails().getProfileImage().getImageUrl());
});
}
@Test
void addressDTOtoAddress() {
AddressDTO addressDTO = getAddressDTO();
Address address = addressMapper.addressDTOtoAddress(addressDTO);
assertAll("Check if values were properly bound",
() -> {
assertEquals(addressDTO.getCity(), address.getCity());
assertEquals(addressDTO.getUserDetails().getFirstName(), address.getUserDetails().getFirstName());
assertEquals(addressDTO.getUserDetails().getUser().getUsername(), address.getUserDetails().getUser().getUsername());
assertEquals(addressDTO.getUserDetails().getContact().getEmail(), address.getUserDetails().getContact().getEmail());
assertEquals(addressDTO.getUserDetails().getProfileImage().getImageUrl(), address.getUserDetails().getProfileImage().getImageUrl());
});
}
我的想法是创建更通用的东西,例如:
private<T, S> void assertObject(T expected, S actual) {
assertAll("Check if values were properly bound",
() -> {
assertEquals(expected.getCity(), actual.getCity());
assertEquals(expected.getUserDetails().getFirstName(), actual.getUserDetails().getFirstName());
assertEquals(expected.getUserDetails().getUser().getUsername(), actual.getUserDetails().getUser().getUsername());
assertEquals(expected.getUserDetails().getContact().getEmail(), actual.getUserDetails().getContact().getEmail());
assertEquals(expected.getUserDetails().getProfileImage().getImageUrl(), actual.getUserDetails().getProfileImage().getImageUrl());
});
}
但是,即使它们是相同的对象,它们也没有任何共同之处。如何实现地址和地址DTO既可以是实际的也可以是预期的hmm可互换的东西?
编辑
根据 Aaron Digulla 的回答,我做了一些更改,希望它能帮助有同样疑问的人。如果有人知道任何其他选项,请在评论部分发表。
@Test
void addressToAddressDTO() {
Address expected = getAddress();
AddressDTO actual = addressMapper.addressToAddressDTO(expected);
assertEquals(
mergeAddressDataToString(expected),
actual.getCity() + "," +
actual.getUserDetails().getFirstName() + "," +
actual.getUserDetails().getUser().getUsername() + "," +
actual.getUserDetails().getContact().getEmail() + "," +
actual.getUserDetails().getProfileImage().getImageUrl()
);
}
@Test
void addressDTOtoAddress() {
AddressDTO expected = getAddressDTO();
Address actual = addressMapper.addressDTOtoAddress(expected);
assertEquals(
expected.getCity() + "," +
expected.getUserDetails().getFirstName() + "," +
expected.getUserDetails().getUser().getUsername() + "," +
expected.getUserDetails().getContact().getEmail() + "," +
expected.getUserDetails().getProfileImage().getImageUrl(),
mergeAddressDataToString(actual)
);
}
private String mergeAddressDataToString(Address address) {
StringJoiner stringJoiner = new StringJoiner(",");
stringJoiner.add(address.getCity());
stringJoiner.add(address.getUserDetails().getFirstName());
stringJoiner.add(address.getUserDetails().getUser().getUsername());
stringJoiner.add(address.getUserDetails().getContact().getEmail());
stringJoiner.add(address.getUserDetails().getProfileImage().getImageUrl());
return stringJoiner.toString();
}
解决方案
toString()
当多个测试需要共享它时,我通常会为测试中的对象或测试实用程序类编写自定义方法。这样,我可以使用单个assertEquals()
.
我可以使用换行符使断言在 IDE 中更具可读性:
assertEquals(
"city=Foo\n" +
"firstName=John\n" +
"user=doe\n" +
....
, toString(actual));
当您必须检查值列表时,它也可以很好地工作:
...
, list.stream().map(this::toString).collect(Collectors.joining("\n---\n"));
这里最大的优势是你可以一次得到所有的不匹配。您还可以调整toString()
处理极端情况的方法(例如仅比较大型列表的元素数量或舍入小数)。
它还使代码易于理解。在许多情况下,它还可以节省您编写代码以填充expected
您需要的所有对象的时间。当多个测试应该产生相同的结果时,测试甚至可以共享预期的字符串。
当测试因输出更改而中断时,我可以选择整个字符串并将其替换为新输出。IDE 将为我进行格式化。
推荐阅读
- generics - 除了使用带有相关常量的特征之外,还有一种更简单的方法来为通用结构配备常量吗?
- java - 如何在不使用任何“ButtonType”控件的情况下在 JavaFx 中创建自定义对话框?
- c++ - 如何在 C++ 中将文本文件的特定行读入 int 类型的数组?
- java - 如何在 Java 中捆绑 getter?
- php - 对 Laravel 查询构建器的 SQL 查询
- r - 将数据帧的每一列除以数据帧的一行
- vba - VBA 代码的结果在 Access 的文本框中不可见
- performance - Flutter:大画布的缩放会降低 FPS
- spring - Spring Data JPA:参数化@Query注解字符串,重构两个相似的@Query方法
- azure-cognitive-services - 如何以编程方式关闭沉浸式阅读器?