Reputation: 352
I'm still not that confident when it comes to write unit tests for more complex methods/classes. My understanding of tdd and unit tests in general is, that you should be able to refactor the implementation of a class / method and have some confidence that you haven't changed it's behaviour
Let me give an example to make things more clear.
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;
}
}
Basically I'm just creating a new Order from a OrderCreationDto. For each order line I have to use the item service to create a new item first. One of my tests would make sure, that a call to itemService.create(...)
is made for each order line with certain arguments.
Since each call to itemService.create(...)
is quite expensive I'd like to refactor the class to create all items in one request .. let's do the changes
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;
}
}
Now I've made the changes and my previously written test fails, even though the behaviour of the class has not changed at all.
Am I missing something? Is it something I have to accept the way it is and simply adjust the written test(s)?
Any thoughts are appreciated
Upvotes: 1
Views: 158
Reputation: 31484
Am I missing something? Is it something I have to accept the way it is and simply adjust the written test(s)?
No. Yes.
Unit tests do change. You've set your test basing on some class to utilize certain contract (ItemService
). Changing this contract requires you to change the test, as simple as that.
Think about it differently: from tested class client's point of view, nothing changed and behavior is the same (that's good). However, from ItemService
client point of view, you've intoduced breaking change (contract change). Who's the ItemService
client? In this case, OrderService
and its tests.
Also, you should consider whether state verification (asserting state of OrderService
products) won't be better fit than behavior verification (verifying mock was called). Former one usually makes your tests less fragile to such changes, but neither will make the need of introducing changes to go away.
Upvotes: 1