0

私は Moq を使用していますが、単純なモック シナリオのように見えるものを単体テストに渡すことができないようです。

Product p = new Product();
var rep = new Mock<IProductRepository>();
rep.Expect(x => x.GetProductById(1)).Returns(p);
p = rep.Object.GetProductById(1);
Assert.AreEqual(1, p.ProductId);  //Assert.AreEqual failed. Expected:<1>. Actual:<0>.

私が間違っていることについての指針はありますか?私のユニットテストレポート:-

Assert.AreEqual が失敗しました。予想:<1>。実際:<0>。

4

6 に答える 6

4

テストでモックオブジェクトを使用する方法のポイントが欠けていると思います...

あなたがしていることは、同時にテストしながら ProductRepository オブジェクトをモックすることです。それはあまり意味がありません。テストしているオブジェクトをモックしないでください。

テストしたいクラス ProductService があり、それが別のクラス IProductRepository に依存しているとします。ProductService をテストするときは、依存関係である IProductRepository をモックする必要があります。これにより、テスト中のクラスとその (モックされた) 依存関係の間の相互作用を完全に制御できます。

そうすることで、アサーションは、テスト対象のクラスである ProductService が期待することに基づいたものになります。たとえば、 のようなものを使用して ProductService を呼び出す場合productService.GetProductById(1)、ProductService オブジェクトは正しいパラメーターを使用して IProductRepository メソッドを 1 回だけ呼び出すことが期待されますrepository.GetProductById(1)。また、IProductRepository が指定したのと同じオブジェクトを ProductService が返すことも期待できます。リポジトリが何をするかに関係なく、それは ProductService の責任です。

そうは言っても、テストは次のようになります。

//Arrange
int testId = 1;
var fakeProduct = new Product{ Id = testId };
var mockRepo = new Mock<IRepository>();
var productService = new ProductService(mockRepo);
mockRepo.Expect(repo => repo.GetProductById(testId)).Returns(fakeProduct);

//Act
Product returnedProduct = productService.GetProductById(testId);

//Assert
mockRepo.Verify(repo => repo.GetProductById(testId), TimesExactly(1));
Assert.AreEqual(returnedProduct.Id, fakeProduct.Id);

私の構文は間違っているかもしれませんが、うまくいけばサンプルはいくつかのポイントを越えます:

  1. テスト中のシステムをモックしない
  2. 依存関係をモックする
  3. 依存関係ではなく、テスト中のシステムの責任に基づいてアサーションを行う
于 2009-11-29T22:30:19.640 に答える
3

オブジェクトを作成し、そのオブジェクトをメソッドの戻り値として設定し、モックがオブジェクトを変更しているかどうかを確認します。これは、モックが意図していないことです。基本的にこれを行っています。

Product getProductById(Product p) { return p; }
...
Product p = new Product();
Assert.AreEqual(1, getProductById(p).ProductID );

新しい製品を作成する場合:

Product p = new Product();

デフォルトの ProductID は 0 だと思うので、文は次のようになります。

 getProductById(p).ProductID

明らかに 0 を返します。

私もここで嘲笑するのは初めてですが、あなたの主張がわかりません。何をテストしようとしていますか?Product クラス、ProductRepository、またはそれらの間の相互作用? それが最初に考えるべきことです。

于 2009-01-29T07:41:54.663 に答える
1

私はあなたのコードを見ていますが、あなたが達成しようとしていることを知っているようには見えません。テストを書く前に、必ず「ここで何を証明しようとしているのか?」という質問をしてください。 作成した製品が返されますが、その ID はデフォルト値 (0) になります。これは想定された動作です。つまり、モッキング フレームワークは正常に動作しています。

テスト ダブル (モック、スタブ、フェイク、スパイなど) は、テスト対象のクラスに共同作業者を提供するためにテストで使用されます。それらは、テスト対象のクラスに興味深い値をフィードしたり、クラスからの呼び出しを受け取ったりしますが、テストの焦点では​​ありません。

テストは現在、テスト double 自体によって返された値をアサートしています。私が理解できることから、コンテキスト外のコード スニペット (スニペット自体は単なる例であり、テスト自体ではありません) について助けを求めているか、無意味な実際のテスト コードです。

私は多くの人がモックフレームワークで自分自身を結びつけるのを見てきました. そのため、まず、独自のテスト doubles を手書きすることをお勧めします。これは、オブジェクト間の相互作用を理解し、何をテストしたいかをより明確に把握するのに役立ちます。繰り返しますが、これは「ここで何を証明しようとしているのか?」という質問に戻ります。

手巻きのテストダブルを使用して目標を達成する方法を理解したら、フレームワークのモックに進むことができます。

于 2009-11-29T21:52:27.433 に答える
0

Gishu re: Product の初期化の見解を支持します。IProductRepository の既定の動作が ProductId '1' によって参照される製品を返すことでない限り、テストは失敗します。

そして、付け加えておきますが、この失敗は賢明な振る舞いのようです。初期化時に ProductRepository を空にしてほしいと思います。

于 2009-01-29T06:26:28.280 に答える
0

期待値 - 戻り値 (p) を設定し、同じ参照を使用して実際の呼び出しの戻り値を格納しているときに、Product インスタンス p を「期待値」として 1 回使用しています。

Assert の失敗に関しては、new Product() は ProductId を 1 に初期化します。デフォルト値の 0 に設定されているようです - したがって、エラーです。

Mock フレームワークが機能していると思います。

于 2009-01-29T06:11:14.440 に答える
0

要点を正確に逃しているわけではありませんが、モッキングは簡単ではありません。

あなたの場合、あなたはそれを持ってIProductRepositoryいると思いますProducts. Productsはデフォルトで に追加されていないと仮定しProductRepositortます (以前の投稿による)。また、 a を参照するProductには、 a が必要であると仮定します (ちなみに、実際にはmutatorproductIdを介して変更する必要があります)。

Productからを取得したい場合は、モック フレームワークを使用して をProductRepository追加する必要があると思います( moq サイトでは、ページの上部に登録と検証の例が示されています) 。s にデフォルトの識別子を追加するか (推奨されません)、または に追加する前に に識別子を追加します。ProductProductRepostoryProductProductProductRepository

于 2009-01-29T06:51:29.883 に答える