Adedi ile belirli bir parametreyi doğrulama


170
public void SubmitMessagesToQueue_OneMessage_SubmitSuccessfully()
{
    var messageServiceClientMock = new Mock<IMessageServiceClient>();
    var queueableMessage = CreateSingleQueueableMessage();
    var message = queueableMessage[0];
    var xml = QueueableMessageAsXml(queueableMessage);
    messageServiceClientMock.Setup(proxy => proxy.SubmitMessage(xml)).Verifiable();
    //messageServiceClientMock.Setup(proxy => proxy.SubmitMessage(It.IsAny<XmlElement>())).Verifiable();

    var serviceProxyFactoryStub = new Mock<IMessageServiceClientFactory>();
    serviceProxyFactoryStub.Setup(proxyFactory => proxyFactory.CreateProxy()).Returns(essageServiceClientMock.Object);
    var loggerStub = new Mock<ILogger>();

    var client = new MessageClient(serviceProxyFactoryStub.Object, loggerStub.Object);
    client.SubmitMessagesToQueue(new List<IMessageRequestDTO> {message});

    //messageServiceClientMock.Verify(proxy => proxy.SubmitMessage(xml), Times.Once());
    messageServiceClientMock.Verify();
}

Moq kullanmaya başlıyorum ve biraz mücadele ediyorum. MessageServiceClient bir XmlElement olan doğru parametreyi aldığını doğrulamaya çalışıyorum, ancak çalışması için herhangi bir yol bulamıyorum. Yalnızca belirli bir değeri kontrol etmediğimde çalışır.

Herhangi bir fikir?

Kısmi cevap: Proxy'ye gönderilen xml'nin doğru olduğunu test etmenin bir yolunu buldum, ancak yine de bunu yapmanın doğru yolu olduğunu düşünmüyorum.

public void SubmitMessagesToQueue_OneMessage_SubmitSuccessfully()
{
    var messageServiceClientMock = new Mock<IMessageServiceClient>();
    messageServiceClientMock.Setup(proxy => proxy.SubmitMessage(It.IsAny<XmlElement>())).Verifiable();
    var serviceProxyFactoryStub = new Mock<IMessageServiceClientFactory>();
    serviceProxyFactoryStub.Setup(proxyFactory => proxyFactory.CreateProxy()).Returns(messageServiceClientMock.Object);
    var loggerStub = new Mock<ILogger>();

    var client = new MessageClient(serviceProxyFactoryStub.Object, loggerStub.Object);
    var message = CreateMessage();
    client.SubmitMessagesToQueue(new List<IMessageRequestDTO> {message});

    messageServiceClientMock.Verify(proxy => proxy.SubmitMessage(It.Is<XmlElement>(xmlElement => XMLDeserializer<QueueableMessage>.Deserialize(xmlElement).Messages.Contains(message))), Times.Once());
}

Bu arada, ifadeyi Doğrulama çağrısından nasıl çıkarabilirim?

Yanıtlar:


251

Doğrulama mantığı önemsiz değilse, büyük bir lambda yöntemi yazmak dağınık olacaktır (örneğin gösterdiği gibi). Tüm test ifadelerini ayrı bir yöntemle koyabilirsiniz, ancak bunu yapmak istemiyorum çünkü test kodunu okuma akışını bozuyor.

Başka bir seçenek, alay edilen yönteme iletilen değeri saklamak için Kurulum çağrısında geri arama kullanmak ve ardından Assertdoğrulamak için standart yöntemler yazmaktır . Örneğin:

// Arrange
MyObject saveObject;
mock.Setup(c => c.Method(It.IsAny<int>(), It.IsAny<MyObject>()))
        .Callback<int, MyObject>((i, obj) => saveObject = obj)
        .Returns("xyzzy");

// Act
// ...

// Assert
// Verify Method was called once only
mock.Verify(c => c.Method(It.IsAny<int>(), It.IsAny<MyObject>()), Times.Once());
// Assert about saveObject
Assert.That(saveObject.TheProperty, Is.EqualTo(2));

6
Bu yaklaşımın büyük bir yararı, nesnenin nasıl yanlış olduğuna dair belirli test hataları vermesidir (her birini ayrı ayrı test ettiğinizde).
Rob Kilisesi

1
Bunu yapan tek kişi olduğumu düşündüm, makul bir yaklaşım olduğunu görmekten memnunum!
Appleby

3
Bunu, Mayo başına olarak <MyObject> (validator) kullanmanın, lambda'nın bir parçası olarak parametre değerini kaydetmenin biraz garip yolundan kaçınması nedeniyle daha iyi olduğunu düşünüyorum
stevec

Bu iplik, örneğin testleri paralel çalıştırırken güvenli midir?
Anton Tolken

@AntonTolken Denemedim, ancak örneğimde, güncellenen nesne yerel bir değişkendir (saveObject), bu yüzden iş parçacığı güvenli olmalıdır.
Zengin Tebb

113

Aramaları aynı şekilde doğruladım - bunun doğru yol olduğuna inanıyorum.

mockSomething.Verify(ms => ms.Method(
    It.IsAny<int>(), 
    It.Is<MyObject>(mo => mo.Id == 5 && mo.description == "test")
  ), Times.Once());

Lambda ifadeniz uygunsuz hale gelirse, MyObjectgiriş ve çıkışlar true/ false... olarak alan bir işlev oluşturabilirsiniz .

mockSomething.Verify(ms => ms.Method(
    It.IsAny<int>(), 
    It.Is<MyObject>(mo => MyObjectFunc(mo))
  ), Times.Once());

private bool MyObjectFunc(MyObject myObject)
{
  return myObject.Id == 5 && myObject.description == "test";
}

Ayrıca, Mock ile ilgili bir hata olduğunu unutmayın; burada hata mesajı, yöntemin hiç çağrılmadığında birden çok kez çağrıldığını belirtir. Şimdiye kadar düzeltmiş olabilirler - ancak bu mesajı görürseniz yöntemin gerçekten çağrıldığını doğrulamayı düşünebilirsiniz.

DÜZENLEME: Burada, bir listedeki her nesne (örneğin) için bir işlev çağırdığınızı doğrulamak istediğiniz senaryolar için birden çok kez doğrulama çağırma örneği verilmiştir.

foreach (var item in myList)
  mockRepository.Verify(mr => mr.Update(
    It.Is<MyObject>(i => i.Id == item.Id && i.LastUpdated == item.LastUpdated),
    Times.Once());

Kurulum için aynı yaklaşım ...

foreach (var item in myList) {
  var stuff = ... // some result specific to the item
  this.mockRepository
    .Setup(mr => mr.GetStuff(item.itemId))
    .Returns(stuff);
}

Dolayısıyla, bu itemId için GetStuff her çağrıldığında, o öğeye özgü şeyler döndürür. Alternatif olarak, itemId öğesini girdi olarak alan ve bir şeyler döndüren bir işlevi kullanabilirsiniz.

this.mockRepository
    .Setup(mr => mr.GetStuff(It.IsAny<int>()))
    .Returns((int id) => SomeFunctionThatReturnsStuff(id));

Bir blogda bir süre önce gördüğüm başka bir yöntem (belki de Phil Haack?) Bir tür dequeue nesnesinden dönen kurulum vardı - işlev her çağrıldığında bir öğeyi kuyruktan çekerdi.


1
Teşekkürler, bana mantıklı geliyor. Hala anlayamadığım, Kurulum veya Doğrulama'da ayrıntıları belirtmektir. Oldukça kafa karıştırıcı. Şu anda, Kurulum'daki herhangi bir şeye izin veriyorum ve Doğrulama'daki değerleri belirtiyorum.
Luis Mirabal

Birden fazla arama olduğunda mesajları nasıl kontrol edebileceğimi düşünüyorsun? İstemci mesajları alır ve birden fazla queueableMessage oluşturabilir, bu da birden fazla çağrıda sonuçlanır ve bu çağrıların her birinde farklı mesajları kontrol etmeliyim. Hala genel olarak birim testlerle uğraşıyorum, henüz çok tanımadım.
Luis Mirabal

Bunu nasıl yapman gerektiği konusunda sihirli bir gümüş kurşun olduğunu sanmıyorum. Bu pratik gerektirir ve daha iyi olmaya başlar. Benim için, sadece bunları karşılaştırmak için bir şeyim olduğunda ve bu parametreyi başka bir testte test etmediğimde belirtiyorum. Birden fazla çağrıya gelince, birkaç yaklaşım vardır. Birden çok kez çağrılan bir işlevi ayarlamak ve doğrulamak için, genellikle beklediğim her çağrı için kurulum veya doğrulama (Times.Once ()) - genellikle bir for döngüsü ile. Her bir aramayı izole etmek için belirli parametreleri kullanabilirsiniz.
Mayo

Birden fazla çağrı için bazı örnekler ekledim - yukarıdaki cevaba bakınız.
Mayo

1
"Ayrıca, Mock ile ilgili bir hata olduğunu unutmayın; burada hata mesajı, yöntemin hiç çağrılmadığında birden çok kez çağrıldığını belirtir. Şimdiye kadar düzeltmiş olabilirler - ancak bu mesajı görürseniz, bunu doğrulamayı düşünebilirsiniz. yöntem aslında çağrıldı. " - Böyle bir hata alay kütüphanesi IMHO'yu tamamen geçersiz kılar. Ne kadar ironik onlar için uygun test kodu yoktu :-)
Gianluca Ghettini

20

Bunu yapmanın daha basit bir yolu:

ObjectA.Verify(
    a => a.Execute(
        It.Is<Params>(p => p.Id == 7)
    )
);

Bu çalışma almak için görünmüyor, benim yöntem Code.WRCC ile bir parametre olarak çağrıldığını doğrulamaya çalışıyorum. Ama test her zaman geçiyor, geçilen parametre WRDD olmasına rağmen .. m.Setup(x => x.CreateSR(Code.WRDD)).ReturnsAsync(0); await ClassUnderTest.CompleteCC(accountKey, It.IsAny<int>(), mockRequest); m.Verify(x => x.CreateSR(It.Is<Code>(p => p == Code.WRCC)), Times.Once());
Greg Quinn

1

Ben inanıyorum ki aslında ADEDI eşitlik kontrol edecek sorun. Ve, XmlElement Eşittirleri geçersiz kılmadığından, uygulama referans eşitliğini kontrol edecektir.

Özel bir nesne kullanamazsınız, böylece eşitleri geçersiz kılabilirsiniz?


Evet, sonunda bunu yaptım. Sorunun Xml'yi kontrol ettiğini fark ettim. Sorunun ikinci bölümünde, bir nesneye
xml'nin

1

Bunlardan biri de vardı, ancak eylemin parametresi hiçbir kamusal özelliği olmayan bir arayüzdü. Ayrı bir yöntemle It.Is () kullanarak sona erdi ve bu yöntem içinde arabirimin biraz alay etmek zorunda kaldı

public interface IQuery
{
    IQuery SetSomeFields(string info);
}

void DoSomeQuerying(Action<IQuery> queryThing);

mockedObject.Setup(m => m.DoSomeQuerying(It.Is<Action<IQuery>>(q => MyCheckingMethod(q)));

private bool MyCheckingMethod(Action<IQuery> queryAction)
{
    var mockQuery = new Mock<IQuery>();
    mockQuery.Setup(m => m.SetSomeFields(It.Is<string>(s => s.MeetsSomeCondition())
    queryAction.Invoke(mockQuery.Object);
    mockQuery.Verify(m => m.SetSomeFields(It.Is<string>(s => s.MeetsSomeCondition(), Times.Once)
    return true
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.