これが私のコードの仕組みです。サードパーティのショッピングAPIに保存されている、ショッピングカートの注文に似たものの現在の状態を表すオブジェクトがあります。私のコントローラーコードで、私は呼び出すことができるようにしたいです:
myOrder.updateQuantity(2);
実際に、第三者にメッセージを送信するためには、第三者にも同様THISために固有のいくつかのことを、知っている必要がありorderID、かつloginID、アプリケーションの存続期間中に変化しないであろう。
私が作成したときにmyOrder、もともと、私は注射MessageFactory知っています、loginID。次に、updateQuantityが呼び出されると、Orderパスがを通過しorderIDます。制御コードは簡単に記述できます。別のスレッドがコールバックを処理し、Order変更が成功した場合は更新Orderし、変更が失敗した場合は変更が失敗したことを通知します。
問題はテストです。のでOrder、オブジェクトが依存するMessageFactory、それが必要MessageFactory実際返すようにMessageSを(それが呼び出すこと.setOrderID()例えば、上)、今私は非常に複雑に設定する必要がMessageFactoryモックを。さらに、「モックがモックを返すたびに妖精が死ぬ」ので、私は妖精を殺したくありません。
コントローラーのコードを単純に保ちながら、この問題を解決するにはどうすればよいですか?私はこの質問を読みました:https : //stackoverflow.com/questions/791940/law-of-demeter-on-factory-pattern-and-dependency-injectionしかし、それはテストの問題について話していなかったので助けにはなりませんでした。
私が考えたいくつかの解決策:
- どういうわけか、ファクトリメソッドが実際のオブジェクトを返す必要がないようにコードをリファクタリングします。おそらく、それは工場ではなく、
MessageSender? - のテスト専用実装を作成し
MessageFactory、それを注入します。
コードはかなり複雑です。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メッセージを送信すること、または正しいメッセージを送信することを確認しようとしていますか?
verify(messageMock).setQuantity(2)、とverify(layer).send(messageMock);。またupdateQuantity場合はfalseを返す必要がありOrder、既に保留中の更新を持っていますが、私はsscce上の理由からそのコードを省略しました。
Orderオブジェクトとに対して作成した関連コードを表示する必要があると思いますMessageFactory。これは良い説明ですが、明確な回答で直接取り組むのは少し抽象的です。