web-dev-qa-db-ja.com

Moqをよりよく理解するために助けが必要

私はMoqのドキュメントを見てきましたが、コメントが短すぎて、Moqが実行できる各ことを理解できません。

私が最初に得られないのはIt.IsAny<string>(). //example using stringです

単に何らかの価値を置くよりもこれを使用する利点はありますか?値を気にしないのならこれを使うと言われているのは知っていますが、値を気にしないのなら「a」か何かをするだけではいけませんか?これはもっとタイピングしているようです。

第二に、あなたが価値を気にしないときの例はいつですか? Moqは物事を一致させるための価値が必要だと思いました。

_It.Is<>_の目的や使用方法がまったくわかりません。例とそれが何を示しているのか理解できません。

次に、Times(およびそのAtMostメソッドなど)をいつ使用するかがわかりません。なぜ何かが設定される回数を制限するのですか? 2回使用する必要のあるAppConfig値があります。たとえば、1回に制限したいのはなぜですか?これはテストを失敗させるだけです。これは、他の人があなたのコードなどに別のものを追加するのを防ぐためですか?

mock.SetupAllProperties();の使用方法がわかりません。プロパティの設定方法は何ですか?

プロパティを設定する方法がたくさんある理由と、それらの違いについてもわかりません。ドキュメントには次のものがあります。

_SetupGet(of property)
SetupGet<TProperty>
_

Moqの多くのものが_()_と_<>_を示していることに気づきました-それらの違いは何ですか、そしてそれらは使用中にどのように見えるでしょうか?

また、なぜ彼らがSetupGetを持っているのかわかりません。 SetupSetを使用してプロパティを設定しませんか? SetupSetには、ドキュメントで使用する5つの異なる方法があります。さらに、SetupPropertyと呼ばれる別のもの。だから、なぜこんなに多いのかわかりません。

ちなみに、ラムダで使用される変数が他のラムダから独立しているかどうか疑問に思っています。例えば。:

_mock.setup(m => m.Test);
stop.setup(m => m.Test);
_

これは問題ありませんか、それとも変数mの間に競合がありますか?

最後に、私は このビデオを見て でしたが、VisualStudioが表示されているかどうか疑問に思っています。彼のインテリセンスは異なって見えます。彼のために電球がポップアップし(NetBeansの辛い記憶を呼び戻すので、私はそうしません)、1つのオープニングブレースからクロージングブレースなどに線があります。

ありがとう:)

43
chobo2

It.IsAny/It.Is

これらは、テスト対象のコード内で新しい参照型を渡すときに役立ちます。たとえば、次のような方法がある場合:-

public void CreatePerson(string name, int age) {
    Person person = new Person(name, age);
    _personRepository.Add(person);
}

Addメソッドがリポジトリで呼び出されていることを確認することをお勧めします

[Test]
public void Create_Person_Calls_Add_On_Repository () {
    Mock<IPersonRepository> mockRepository = new Mock<IPersonRepository>();
    PersonManager manager = new PersonManager(mockRepository.Object);
    manager.CreatePerson("Bob", 12);
    mockRepository.Verify(p => p.Add(It.IsAny<Person>()));
}

このテストをより明確にしたい場合は、それを使用できます。述語を指定することにより、personオブジェクトが一致する必要があります

[Test]
public void Create_Person_Calls_Add_On_Repository () {
    Mock<IPersonRepository> mockRepository = new Mock<IPersonRepository>();
    PersonManager manager = new PersonManager(mockRepository.Object);
    manager.CreatePerson("Bob", 12);
    mockRepository.Verify(pr => pr.Add(It.Is<Person>(p => p.Age == 12)));
}

このように、addメソッドの呼び出しに使用されたpersonオブジェクトのageプロパティが12に設定されていない場合、テストは例外を通過します。

タイムズ

次のような方法がある場合:-

public void PayPensionContribution(Person person) {
    if (person.Age > 65 || person.Age < 18) return;
    //Do some complex logic
    _pensionService.Pay(500M);
}

テストしたいことの1つは、65歳以上の人がメソッドに渡されたときにpayメソッドが呼び出されないことです。

[Test]
public void Someone_over_65_does_not_pay_a_pension_contribution() {
    Mock<IPensionService> mockPensionService = new Mock<IPensionService>();
    Person p = new Person("test", 66);
    PensionCalculator calc = new PensionCalculator(mockPensionService.Object);
    calc.PayPensionContribution(p);
    mockPensionService.Verify(ps => ps.Pay(It.IsAny<decimal>()), Times.Never());
}

同様に、コレクションを繰り返し処理し、コレクション内の各アイテムのメソッドを呼び出して、それが特定の回数呼び出されていることを確認したい場合や、単に気にしない場合を想像することもできます。 。

SetupGet/SetupSet

これらの人たちに注意する必要があるのは、モックを設定する方法ではなく、コードがモックとどのように相互作用しているかを反映しているということです。

public static void SetAuditProperties(IAuditable auditable) {
    auditable.ModifiedBy = Thread.CurrentPrincipal.Identity.Name;
}

この場合、コードはIPrincipalの現在のインスタンスのNameプロパティを取得している間に、IAuditableインスタンスのModifiedByプロパティを設定しています。

[Test]
public void Accesses_Name_Of_Current_Principal_When_Setting_ModifiedBy() {
    Mock<IPrincipal> mockPrincipal = new Mock<IPrincipal>();
    Mock<IAuditable> mockAuditable = new Mock<IAuditable>();

    mockPrincipal.SetupGet(p => p.Identity.Name).Returns("test");

    Thread.CurrentPrincipal = mockPrincipal.Object;
    AuditManager.SetAuditProperties(mockAuditable.Object);

    mockPrincipal.VerifyGet(p => p.Identity.Name);
    mockAuditable.VerifySet(a => a.ModifiedBy = "test");
}

この場合、IPrincipalのモックにnameプロパティを設定しているため、プロパティ自体を設定していないIdentityのNameプロパティでgetterが呼び出されたときに「test」が返されます。

SetupProperty/SetupAllProperties

上記のテストを読んで変更された場合は

[Test]
public void Accesses_Name_Of_Current_Principal_When_Setting_ModifiedBy() {
    Mock<IPrincipal> mockPrincipal = new Mock<IPrincipal>();
    Mock<IAuditable> mockAuditable = new Mock<IAuditable>();
    mockPrincipal.SetupGet(p => p.Identity.Name).Returns("test");

    var auditable = mockAuditable.Object;

    Thread.CurrentPrincipal = mockPrincipal.Object;
    AuditManager.SetAuditProperties(auditable);

    Assert.AreEqual("test", auditable.ModifiedBy);
}

テストは失敗します。これは、Moqによって作成されたプロキシは、指示がない限り、プロパティのsetメソッドで実際には何も実行しないためです。影響を受けるモックオブジェクトはこのように見えます

public class AuditableMock : IAuditable {
     public string ModifiedBy { get { return null; } set { } }

} 

テストに合格するには、Moqに、標準のプロパティ動作を持つようにプロパティを設定するように指示する必要があります。 SetupPropertyを呼び出すことでこれを行うことができ、モックは次のようになります。

public class AuditableMock : IAuditable {
     public string ModifiedBy { get; set; }
} 

値「test」がモックに対して保存されるため、上記のテストは合格になります。複雑なオブジェクトをモックする場合は、すべてのプロパティに対してこれを実行する必要があるため、SetupAllPropertiesショートカットを使用します。

最後に、IDEの電球はresharperプラグインです。

105
John Foster

プロパティの正確な値を気にしない場合は、正確な値が重要ではないという事実を明示しているため、.IsAnyを使用することをお勧めします。 「abc」としてハードコーディングした場合、テストしているコードが「a」で始まるか、「c」で終わるか、3文字の長さであるかなどに依存するかどうかは明確ではありません。

4
Andy_Vulhop