java - JUnit - 如何以不同的参数以相同的方法测试重复指令?
问题描述
我有一个更新方法,但我在进行单元测试时遇到了麻烦。在该方法中,我需要验证要更改的对象是否存在于数据库中,并且我还需要检查用户插入的新数据是否会导致记录重复。为此,我在两个不同的时间使用 a 在数据库中进行搜索findById()
:
public void update(Form form, Long storeCode, Long productCode, Long purchaseQuantity) {
var id = new PrimaryKeyBuilder(DiscountPK.builder().build()).build(storeCode,productCode, purchaseQuantity);
var targetToUpdate = repository.findById(id).orElseThrow(NotFoundException::new);
var dataToInsert = SerializationUtils.clone(id);
dataToInsert.setPurchaseQuantity(form.getPurchaseQuantity());
var newPk = repository.findById(dataToInsert);
throwExceptionIf(newPk.isPresent(), new DuplicatedPkException());
targetToUpdate.getId().setPurchaseQuantity(form.getPurchaseQuantity());
targetToUpdate.setDiscountPercentage(form.getDiscountPercentage());
repository.save(targetToUpdate);
}
问题是:我无法findById()
在单元测试中区分这两条指令。我没有成功通过它,而是抛出NotFoundException
了我的第一个验证。就好像第一given()
条语句被忽略,只考虑第二条语句
@Test
public void update_successfully() {
var targetToUpdate = ObjectFactory.createMain();
var form = FormFactory.createUpdateForm();
var id = ObjectFactory.createFirstAux();
var dataToInsert = ObjectFactory.createSecondAux();
given(repository.findById(id)).willReturn(Optional.of(targetToUpdate));
given(repository.findById(dataToInsert)).willReturn(Optional.empty());
given(repository.save(any())).willReturn(targetToUpdate);
service.update(form, STORE_CODE, PRODUCT_CODE, PURCHASE_QUANTITY);
verify(repository).save(targetToUpdate);
}
奖励代码:构建传入对象的类findById()
public class PrimaryKeyBuilder {
private final DiscountPK id;
public PrimaryKeyBuilder(DiscountPK id) {
this.id = id;
}
public DiscountPK build(Long storeCode, Long productCode, Long purchaseQuantity) {
id.setPurchaseBoxQuantity(purchaseBoxQuantity);
id.setProduct(Product.builder().id(ProductPK
.builder().productCode(productCode).store(Store.builder().code(storeCode).build()).build()).build());
return id;
}
}
解决方案
使用given
or定义模拟行为时when
,您需要提供与被测试代码将提供的参数相匹配的参数。Mockito文档解释说:“Mockito 以自然 java 风格验证参数值:通过使用equals()
方法。”
如果DiscountPK
该类没有覆盖该equals
方法,则将java.lang.Object
使用默认实现。这会比较对象身份,并且仅true
在两个对象是同一实例时才返回。
如果您可以修改类,最直接的解决方案DiscountPK
是覆盖该类中的equals
和hashCode
方法,以根据其包含的值定义相等性。假设DiscountPK
该类仅包含两个字段,名为purchaseBoxQuantity
和product
,您可以使用java.util.Objects
该类以这种方式定义它们:
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DiscountPK that = (DiscountPK) o;
return Objects.equals(purchaseBoxQuantity, that.purchaseBoxQuantity) && product.equals(that.product);
}
@Override
public int hashCode() {
return Objects.hash(purchaseBoxQuantity, product);
}
这也假设Product
该类定义equals
和hashCode
。
请注意,尽管 Mockito 仅使用equals
方法,而不使用hashCode
,但始终建议在覆盖hashCode
时覆盖equals
,以确保相等的对象也具有相等的哈希码。
我还建议使主键类不可变。这使得它们更容易推理,因为实体主键的内容永远不会改变。它还确保 的返回值hashCode
不会在对象的生命周期内发生变化,这可能会导致错误。
推荐阅读
- gradle - 如何在 gradle 项目中配置依赖项,使其也可以作为子模块工作?
- python - 同一脚本中的多个 seleniumwire 请求
- python - 使用 map 函数将状态转换为新数据帧列中的区域。所有行显示为 NaN。我究竟做错了什么?
- java - 数组已排序,但两个索引不正确
- c++ - 具有非类型模板的结构的 C++ 实例化
- testing - 如何通过常用测试动态生成测试用例?
- python-3.x - 如何在不使用两个嵌套循环的情况下添加两个列表的所有可能组合?
- python - 使用 asrtoolkit 的 wer 函数,但需要帮助来降低字符错误率
- c# - 在 Picturebox 中显示指纹
- javascript - 在ES6中使用单个公共键合并X个对象数组的数组