Đây là cách mã của tôi hoạt động. Tôi có một đối tượng đại diện cho trạng thái hiện tại của một thứ gì đó giống với đơn đặt hàng trong giỏ hàng, được lưu trữ trong API mua sắm của bên thứ 3. Trong mã điều khiển của tôi, tôi muốn có thể gọi:
myOrder.updateQuantity(2);
Để thực sự gửi tin nhắn cho bên thứ ba, bên thứ ba cũng cần biết một số điều cụ thể theo thứ tự NÀY, như orderID
, và loginID
, sẽ không thay đổi trong vòng đời của ứng dụng.
Vì vậy, khi tôi tạo myOrder
ban đầu, tôi tiêm một MessageFactory
, mà biết loginID
. Sau đó, khi updateQuantity
được gọi, Order
đi qua orderID
. Mã kiểm soát rất dễ viết. Một luồng khác xử lý cuộc gọi lại và cập nhật Order
nếu thay đổi của nó thành công hoặc thông báo Order
rằng thay đổi của nó không thành công nếu không.
Vấn đề là thử nghiệm. Bởi vì Order
đối tượng phụ thuộc vào a MessageFactory
và nó cần MessageFactory
trả về Message
s thực tế ( .setOrderID()
ví dụ như nó gọi ), nên bây giờ tôi phải thiết lập các giả rất phức tạp MessageFactory
. Ngoài ra, tôi không muốn giết bất kỳ nàng tiên nào, vì "Mỗi khi một Mock trả lại một Mock, một nàng tiên chết."
Làm thế nào tôi có thể giải quyết vấn đề này trong khi giữ mã điều khiển đơn giản như vậy? Tôi đã đọc câu hỏi này: /programming/791940/law-of-demeter-on-factory-potype-and-dependency-injection nhưng nó không giúp ích gì vì nó không nói về vấn đề kiểm tra .
Một vài giải pháp tôi đã nghĩ đến:
- Bằng cách nào đó, cấu trúc lại mã để không yêu cầu phương thức nhà máy trả về các đối tượng thực. Có lẽ nó ít hơn một nhà máy và nhiều hơn một
MessageSender
? - Tạo một triển khai chỉ thử nghiệm
MessageFactory
và tiêm nó.
Mã này có liên quan khá nhiều, đây là nỗ lực của tôi tại một sscce:
public class Order implements UpdateHandler {
private final MessageFactory factory;
private final MessageLayer layer;
private OrderData data;
// Package private constructor, this should only be called by the OrderBuilder object.
Order(OrderBuilder builder, OrderData initial) {
this.factory = builder.getFactory();
this.layer = builder.getLayer();
this.data = original;
}
// Lots of methods like this
public String getItemID() {
return data.getItemID();
}
// Returns true if the message was placed in the outgoing network queue successfully. Doesn't block for receipt, though.
public boolean updateQuantity(int newQuantity) {
Message newMessage = factory.createOrderModification(messageInfo);
// *** THIS IS THE KEY LINE ***
// throws an NPE if factory is a mock.
newMessage.setQuantity(newQuantity);
return layer.send(newMessage);
}
// from interface UpdateHandler
// gets called asynchronously
@Override
public handleUpdate(OrderUpdate update) {
messageInfo.handleUpdate(update);
}
}
layer.send
gửi tin nhắn, hoặc nó gửi tin nhắn chính xác ?
verify(messageMock).setQuantity(2)
, và verify(layer).send(messageMock);
cũng updateQuantity
nên trả về false nếu Order
bản cập nhật đang chờ xử lý, nhưng tôi đã bỏ qua mã đó vì lý do sscce.
Order
đối tượng vàMessageFactory
. Đây là một mô tả tốt, nhưng nó hơi trừu tượng để giải quyết trực tiếp với một câu trả lời rõ ràng.