[解決済み] org.mockito.exceptions.misusing.MissingMethodInvocationException
質問
Junitのテストを実行すると、以下のような例外が発生します。
org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() には引数が必要で、これは 'モックのメソッド呼び出し' である必要があります。 例えば
when(mock.getArticles()).thenReturn(articles);
また、このエラーは以下の理由で表示されることがあります。
- final/private/equals()/hashCode() メソッドのいずれかをスタブにしています。 これらのメソッドは はできません。 スタブ化/検証される。
- when() の内部では、モックではなく他のオブジェクトのメソッドをコールしています。
- モックされたクラスの親がパブリックでない。 これはモックエンジンの制限事項です。
以下は私のコードで、2つ目のwhen文で例外が発生しました。私のテストコードは例外が主張することに違反していなかったと思います。私はしばらく費やしましたが、理解することができませんでした。誰か助けてくれませんか?私がテストする必要があるのは、getPermProductsメソッドです。getPermProductsメソッドでは、isTempProductメソッドを無視したいのです。つまり、p1が来たらfalseを返し、p2が来たらtrueを返すようにしたいのです。
@Named(ProductManager.NAME)
public class ProductManager {
@Resource(name = ProductService.NAME)
private ProductService productService;
public List<Product> getPermProducts(Set<Product> products) {
Iterator<Product> it = products.iterator();
List<Product> cProducts = new ArrayList<Product>();
Product p;
while (it.hasNext()) {
p = it.next();
if (!isTempProduct(p)) {
cProducts.add(p);
}
}
return cProducts;
}
public Boolean isTempProduct(Product product) {
if (product instanceof PermProduct) {
return false;
}
Set<ProductItems> pItems = product.getProductItems();
if (pItems.isEmpty()) {
return false;
}
Iterator<ProductItem> itr = pItems.iterator();
while (itr.hasNext()) {
if (itr.next() instanceof TempItem) {
return true;
}
}
return false;
}
public Product getProduct(Integer productId) {
Product p = productService.getProduct(productId);
return p;
}
}
@RunWith(MockitoJUnitRunner.class)
public class ProductManagerTest {
@InjectMocks
private ProductManager mockProductManager;
@Mock
private ProductService mockProductService;//not being used here
private static final Integer PRODUCT_ID_1 = 1;
private static final Integer PRODUCT_ID_2 = 2;
@Test
public void getProduct(){
Product p1 = mock(PermProduct.class);
p1.setProductId(PRODUCT_ID_1);
when(mockProductManager.getProductId()).thenReturn(PRODUCT_ID_1);
when(mockProductManager.isTempProduct(p1)).thenReturn(false);
Product p2 = mock(TempProduct.class);
p2.setProductId(PRODUCT_ID_2);
when(mockProductManager.isTempProduct(p2)).thenReturn(true);
List<Product> products = Mock(List.class);
products.add(p1);
products.add(p2);
Iterator<Product> pIterator = mock(Iterator.class);
when(prodcuts.iterator()).thenReturn(pIterator);
when(pIterator.hasNext()).thenReturn(true, true, false);
when(pIterator.next()).thenReturn(p1, p2);
asserEquals(1, mockProductManager.getPermProducts(products).size());
}
}
解決策:enterbiosさんの回答に基づいて、私のテストを更新しました。私は部分モックを使いましたが、enterbiosが示唆したように、それは避けるべきですが、時にはそれが必要です。モックされないクラスと部分モックされたクラスを同時に持つことができることがわかりました。
@RunWith(MockitoJUnitRunner.class)
public class ProductManagerTest {
@InjectMocks
private ProductManager productManager;//not being used here
@Mock
private ProductService mockProductService;//not being used here
@Spy
private OtherService other = new OtherService();//not being used here
@InjectMocks
final ProductManager partiallyMockedProductManager = spy(new ProductManager());
private static final Integer PRODUCT_ID_1 = 1;
private static final Integer PRODUCT_ID_2 = 2;
@Test
public void getProduct() {
Product p1 = new PermProduct();
p1.setProductId(PRODUCT_ID_1);
Product p2 = new Product();
p2.setProductId(PRODUCT_ID_2);
List<Product> products = new ArrayList<Product>();
products.add(p1);
products.add(p2);
doReturn(false).when(partiallyMockedProductManager).isTempProduct(p1);
doReturn(true).when(partiallyMockedProductManager).isTempProduct(p2);
assertEquals(1, partiallyMockedProductManager.getPermProducts(products).size());
verify(partiallyMockedProductManager).isTempProduct(p1);
verify(partiallyMockedProductManager).isTempProduct(p2);
}
}
解決方法は?
mockProductManagerは、実はモックではなく、ProductManagerクラスのインスタンスです。テスト済みのオブジェクトをモック化してはいけません。スパイを使えばテスト済みのオブジェクトからいくつかのメソッドをモックすることができますが、醜いレガシーコードと戦っているのでなければ、スパイを使わない、あるいは、スパイについて考えないようにすることをお勧めします。 2番目の 'when' はアサーションに置き換えるべきだと思います。
assertFalse(mockProductManager.isTempProduct(p1));
なぜなら、このテストで本当に確認したいことは、PermProductのすべてのインスタンスに対してproductManager.isTempProduct(p1)がfalseを返すかどうかだからです。いくつかのメソッドコールやオブジェクトの状態の結果を確認するには、アサーションを使用する必要があります。アサーションを使いやすくするために、HamcrestやFESTのような便利なライブラリを見てみましょう ( http://docs.codehaus.org/display/FEST/Fluent+Assertions+Module ). 初心者はFESTの方が簡単だと思います。
関連
-
[解決済み】javaで指定されたファイルが見つからない
-
[解決済み】"|="の意味は何ですか?(パイプ等号演算子)
-
[解決済み】Javaクラスの "型に解決できない"
-
[解決済み】Mockitoでモックからチェックされた例外を投げる
-
[解決済み】 JAVA 変数宣言はここではできない
-
[解決済み】keytoolエラー 鍵屋が改ざんされたか、パスワードが不正確だった場合
-
[解決済み】Eclipseで「JUnitテストが見つかりませんでした。
-
[解決済み】Javaメソッドスタブ
-
[解決済み] java.sql.SQLException を取得しました。ResultSet が終了した後の操作は許可されません。
-
[解決済み] ここで、誤った引数マッチャーが検出されました。Mockitoでは、検証やスタブ以外で引数マッチャーを使用することはできません。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】エラー:'if'のない'else'エラー
-
[解決済み] java.sql.SQLException: ユーザー 'root'@'localhost' (using password: YES) のためのアクセスが拒否されました。
-
[解決済み】Java、"変数名 "を変数に解決することができない
-
[解決済み】Doubleはdereferencedできない?
-
[解決済み】不正な反射的アクセスとは?
-
[解決済み】Eclipseがエラーメッセージ "Java was started but returned exit code = 1" を返す
-
[解決済み】Javaで無限大を実装する方法とは?
-
[解決済み】「java -cp」と「java -jar」の違い?
-
[解決済み] java.sql.SQLException を取得しました。ResultSet が終了した後の操作は許可されません。
-
[解決済み] SQLエラー。0, SQLState: 08S01 通信リンクの失敗 [重複]。