2015-05-30 17 views
5

Używam Moq sparowanego z interfejsem metod. Muszę przetestować, czy metody w tym interfejsie są wykonywane w określonej kolejności, a także pewna liczba razy dla każdego z nich.Czas i kolejność wykonywania metod makrotekcji

Interfejs

public interface IInterface 
{ 
    void MethodOne(string foo); 
    void MethodTwo(string foo); 
} 

Metoda

// MyClass stuff ... 

public async Task Run() 
{ 
    MethodOne("foo"); 
    MethodTwo("foo"); 
} 

// ... 

Testy

pisałem ten test, aby sprawdzić, które metody są wykonywane tylko pewną ilość razy (raz):

[TestMethod] 
public async Task Test() 
{ 
    var mock = new Mock<IInterface>(); 
    var mockSequence = new MockSequence(); 

    var obj = new MyClass(); 
    await obj.Run(); 

    mock.Verify(i=> i.MethodOne("foo"), Times.Once()); 
    mock.Verify(i=> i.MethodTwo("foo"), Times.Once()); 
} 

To działa dobrze ...

Próbowałem już tych testów, aby ustalić, czy pewna sekwencja jest prawidłowo spełniona, ale test zdaje się zawsze mijać.

[TestMethod] 
public async Task Test() 
{ 
    var mock = new Mock<IInterface>(); 
    var mockSequence = new MockSequence(); 

    var obj = new MyClass(); 
    await obj.Run(); 

    mock.InSequence(mockSequence).Setup(i => i.MethodOne("foo")); 
    mock.InSequence(mockSequence).Setup(i => i.MethodTwo("foo")); 
} 

powinien przejść, a nie ...

[TestMethod] 
public async Task Test() 
{ 
    var mock = new Mock<IInterface>(); 
    var mockSequence = new MockSequence(); 

    var obj = new MyClass(); 
    await obj.Run(); 

    mock.InSequence(mockSequence).Setup(i => i.MethodTwo("foo")); // swapped order here 
    mock.InSequence(mockSequence).Setup(i => i.MethodOne("foo")); 
} 

Jeżeli nie przejdzie, ale nie ...

  1. Co muszę zrobić inaczej, aby zweryfikować właściwą kolejność jest spełniony ?
  2. Jak połączyć oba, aby sprawdzić liczbę czasów wykonania ORAZ odpowiednią sekwencję?
+0

Oznaczyłem to jako duplikat, ponieważ dwa pytania wydają się odnosić do tego samego problemu. Jeśli nie, daj mi znać, a ja zagłosuję za ponownym otwarciem. – dcastro

+0

Przeczytałem to pytanie, zanim zadałem to pytanie. To pytanie zostało rozwiązane z odpowiedzią, która mówi, że to błąd w Moq. To było 3 lata temu ... Zakładam, że to nie jest błąd. – kspearrin

+0

Ponownie otworzyłem pytanie – dcastro

Odpowiedz

4

Może to być coś więcej niż temat, ale NSubstitute to świetna, szydercza biblioteka, która radzi sobie z tym bardzo dobrze. W NSubstitute to po prostu:

var mock = Substitute.For<IInterface>(); 
    var obj = new MyClass(); 
    await obj.Run(); 

    Received.InOrder(() => { 
    mock.MethodOne("foo"); 
    mock.MethodTwo("foo"); 
    }); 
+0

Dzięki za sugestię. Spojrzę na to. Wydaje się, że ma znacznie lepsze dokumenty niż Moq. – kspearrin

+0

Tak, a interfejs API jest o wiele przyjemniejszy w użyciu. –

+0

Wow, masz rację. To jest o wiele lepsze. O wiele bardziej intuicyjny. Dam mu kilka, aby sprawdzić, czy ktoś może odpowiedzieć na pytanie, które dotyczy konkretnie Moq. Jeśli nie, dam ci to. – kspearrin

3

Twój przykład testy dla InSequence wydają się być w złej kolejności. Przed wywołaniem metody Run należy wykonać operację Setup. Przyjąłem, że to literówka i że twoje rzeczywiste testy wykonują Setup, a następnie wywołaj obiekt we właściwej kolejności. Nie jest również jasne, w jaki sposób Twoja próbka z IInterface trafia do MyClass. W moim ostatnim przykładzie założyłem, że to jest faktycznie wstrzyknięte ...

Moq na InSequence tylko obsługa wydaje się działać, jeśli używasz rygorystycznych makiet. Jeśli tworzysz Mock takiego:

var mock = new Mock<IInterface>(MockBehavior.Strict); 

Wtedy to będzie działać:

mock.InSequence(mockSequence).Setup(i => i.MethodOne("foo")); 
mock.InSequence(mockSequence).Setup(i => i.MethodTwo("foo")); 

podczas gdy to się nie powiedzie:

mock.InSequence(mockSequence).Setup(i => i.MethodTwo("foo")); // swapped order here 
mock.InSequence(mockSequence).Setup(i => i.MethodOne("foo")); 

Uwaga, błąd, który pochodzi około metoda brakuje Odpowiednia konfiguracja ... zamiast wywoływania jej poza kolejnością, która niekoniecznie jest najłatwiejsza do rozszyfrowania, jeśli się jej nie spodziewasz.

Alternatywne podejście, jeśli nie chcesz/nie możesz używać ścisłych makiet, to zaimplementuj własne sprawdzanie sekwencji za pomocą wywołań zwrotnych.Coś takiego:

int sequence = 1; 

mock.Setup(i => i.MethodOne("foo")) 
    .Callback(()=>Assert.AreEqual(1, sequence++, "Method called out of sequence")); 
mock.Setup(i => i.MethodTwo("foo")) 
    .Callback(() => Assert.AreEqual(2, sequence++, "Method called out of sequence")); 

var obj = new MyClass(mock.Object); 
await obj.Run(); 
Powiązane problemy