在为更复杂的方法/类编写单元测试时,我仍然没有那么自信。我对tdd和单元测试的一般理解是,你应该能够重构一个类/方法的实现,并且有信心你没有改变它的行为
让我举一个例子来说明问题。
public class OrderService implements IOrderService
{
private IItemService itemService;
public Order create(OrderCreationDto dto)
{
Order order = new Order();
order.addItems(createOrderLines(dto.products));
return order;
}
private Set<OrderLine> createOrderItems(List<ProductDto> products)
{
Set<OrderLine> orderLines = new HashSet<>();
for (ProductDto product : products) {
Item item = itemService.create(product.id, product.price);
OrderLine orderLine = new OrderLine();
orderLine.setItemId(item.id);
orderLines.add(orderLine);
}
return orderLines;
}
}
基本上我只是从OrderCreationDto创建一个新订单。对于每个订单行,我必须首先使用商品服务来创建新商品。我的一个测试将确保使用某些参数为每个订单行调用itemService.create(...)
。
由于对itemService.create(...)
的每次调用都非常昂贵,我想重构该课程以在一个请求中创建所有项目..让我们进行更改
public class OrderService implements IOrderService
{
private Set<OrderLine> createOrderItems(List<ProductDto> products)
{
Set<OrderLine> orderLines = new HashSet<>();
BatchItemCreationResponse response = itemService.createAll(products);
for (ProductDto product : products) {
Item item = response.get(product.id, product.price);
...
}
return orderLines;
}
}
现在我已经进行了更改,我之前编写的测试失败了,即使班级的行为完全没有改变。
我错过了什么吗?这是我必须接受它的方式并简单地调整书面测试吗?
感谢任何想法
答案 0 :(得分:1)
我错过了什么吗?这是我必须接受它的方式并简单地调整书面测试吗?
没有。是。
单元测试执行更改。您已根据某些类设置测试以使用某个合同(ItemService
)。更改此合同需要您更改测试,就像那样简单。
以不同的方式思考:从经过测试的类客户端的角度来看,没有任何改变,行为也是一样的(这很好)。但是,从ItemService
客户的角度来看,您已经引入了重大变更(合同变更)。谁是ItemService
客户?在这种情况下,OrderService
及其测试。
此外,您应该考虑状态验证(声明OrderService
产品的状态)是否比行为验证更适合(验证模拟被称为)。前者通常会使你的测试对这些变化不那么脆弱,但两者都不会使引入变化的需要消失。