Moq Callback'i anlamama yardım edebilir misin?


102

Moq kullanarak ve baktım Callbackama nasıl kullanılacağını anlamak için basit bir örnek bulamadım.

Nasıl ve ne zaman kullanılacağını net bir şekilde açıklayan küçük bir çalışma pasajınız var mı?

Yanıtlar:


84

Yenmek zor https://github.com/Moq/moq4/wiki/Quickstart

Yeterince açık değilse, buna doc bug derim ...

DÜZENLEME: Açıklamanıza yanıt olarak ...

SetupYaptığınız her alay yöntemi için, aşağıdaki gibi şeyler belirtebilirsiniz:

  • girdiler üzerindeki kısıtlamalar
  • dönüş değerinin (eğer varsa) türetileceği / yol değeri

.CallbackMekanizma "Şu an tarif edemez, ancak bu şeklinde bir çağrı olduğunda, beni geri arayıp yapılması gerekenleri yapacağız" diyor. Aynı akıcı çağrı zincirinin bir parçası olarak, sonucu (varsa) .Returns" yoluyla kontrol edebilirsiniz . QS örneklerinde, bir örnek, döndürülen değeri her seferinde artırmalarıdır.

Genel olarak, bunun gibi bir mekanizmaya çok sık ihtiyaç duymazsınız (xUnit Test Patterns, Koşullu Mantık Testlerindeki antipattern terimlerine sahiptir) ve ihtiyacınız olanı oluşturmanın daha basit veya yerleşik bir yolu varsa, tercih olarak kullanılır.

Justin Etheredge'in Moq serisindeki 4 bölümden 3'ü bunu kapsıyor ve burada başka bir geri arama örneği var

Geri aramanın basit bir örneği Moq gönderisiyle Geri Aramaları Kullanma'da bulunabilir .


4
Merhaba Ruben Moq'u öğreniyorum ve isterseniz, onu kullanarak nasıl şeyler yapılacağını anlamak için birçok örnek oluşturuyorum. Benim sorunum, onu ne zaman kullanacağımı anlamıyorum. Bu sorunun çözüldüğünü anladığımda kendi kodumu yazacağım.Kendi sözünüzle açıklasaydınız geri aramayı ne zaman kullanırdınız? zaman ayırdığınız için teşekkürler
user9969

19
[Link] 'i yenmek zor mu? Bir şey değil. Bu bağlantı size düzinelerce farklı şeyi nasıl yapacağınızı gösterir , ancak bunlardan herhangi birini neden yapmanız gerektiğini size söylemez . Alay dokümantasyonunda yaygın bir sorundur, buldum. Bulduğum TDD + alayının iyi, net açıklamalarının sayısını sıfır parmakla sayabilirim. Çoğu, eğer sahip olsaydım makaleyi okumama gerek kalmayacak bir bilgi seviyesi varsayar.
Ryan Lundy

@Kyralessa: Ben senin fikrini alıyorum. Şahsen epeyce kitap bilgim vardı, bu yüzden hızlı başlangıç ​​materyalini kesinlikle mükemmel buldum. Maalesef yazının sonunda bağlantı kurduğum daha iyi bir örneğin farkında değilim. Bir tane bulursanız, buraya gönderin ve düzenlemekten memnuniyet
duyarım

"Yapılması gerekeni yapacağım ve size (varsa) geri dönmeniz için sonucu söyleyeceğim" Bunun yanıltıcı olduğunu düşünüyorum, AFAIU'nun Callbackdönüş değeriyle hiçbir ilgisi yok (kod aracılığıyla bağlamadığınız sürece). Temel olarak, yalnızca geri aramanın her çağrıdan önce veya sonra çağrıldığından emin olur ( Returnssırasıyla önce veya sonra zincirlemenize bağlı olarak), düz ve basittir.
Ohad Schneider

1
@OhadSchneider Bağlantımı takiben ... haklısın! Fluent arayüzünün değişip değişmediğini merak ediyorum (ancak Moq'u uzun bir süredir kullanmadığım için yeterince ilgilenmiyor) otomatik tamamlamadan). Düzeltmenin amacınıza hitap etmesini umuyoruz, yoksa bana bildirin
Ruben Bartelink

59

Aşağıda, bir eki işleyen bir Veri Hizmetine gönderilen bir varlığı test etmek için geri arama kullanımına bir örnek verilmiştir.

var mock = new Mock<IDataService>();
DataEntity insertedEntity = null;

mock.Setup(x => x.Insert(It.IsAny<DataEntity>())).Returns(1) 
           .Callback((DataEntity de) => insertedEntity = de);

Alternatif genel yöntem sözdizimi:

mock.Setup(x => x.Insert(It.IsAny<DataEntity>())).Returns(1) 
           .Callback<DataEntity>(de => insertedEntity = de);

O zaman aşağıdaki gibi bir şeyi test edebilirsiniz

Assert.AreEqual("test", insertedEntity.Description, "Wrong Description");

4
Muhtemelen bu özel durum için (duruma veya davranışa karşı testleri ifade etmeye çalışmanıza bağlı olarak), bazı durumlarda testi geçici olarak doldurmak yerine It.Is<T>in a kullanmak daha temiz olabilir Mock.Verify. Ama +1 çünkü bahse girerim bir örnekten en iyi şekilde çalışacak birçok insan vardır.
Ruben Bartelink

11

CallbackMoq'da iki tür vardır . Çağrı dönmeden önce biri olur; diğeri çağrı döndükten sonra gerçekleşir.

var message = "";
mock.Setup(foo => foo.Execute(arg1: "ping", arg2: "pong"))
    .Callback((x, y) =>
    {
        message = "Rally on!";
        Console.WriteLine($"args before returns {x} {y}");
    })
    .Returns(message) // Rally on!
    .Callback((x, y) =>
    {
        message = "Rally over!";
        Console.WriteLine("arg after returns {x} {y}");
    });

Her iki geri aramada da şunları yapabiliriz:

  1. yöntem argümanlarını inceleyin
  2. yakalama yöntemi argümanları
  3. bağlamsal durumu değiştir

2
Aslında, her ikisi de çağrı dönmeden önce gerçekleşir (arayan söz konusu olduğunda). Stackoverflow.com/a/28727099/67824 adresine bakın .
Ohad Schneider

8

Callbackbasitçe, sahte yöntemlerden birine çağrı yapıldığında istediğiniz herhangi bir özel kodu yürütmek için bir araçtır. İşte basit bir örnek:

public interface IFoo
{
    int Bar(bool b);
}

var mock = new Mock<IFoo>();

mock.Setup(mc => mc.Bar(It.IsAny<bool>()))
    .Callback<bool>(b => Console.WriteLine("Bar called with: " + b))
    .Returns(42);

var ret = mock.Object.Bar(true);
Console.WriteLine("Result: " + ret);

// output:
// Bar called with: True
// Result: 42

Geçenlerde bunun için ilginç bir kullanım durumuyla karşılaştım. Varsayalım, taklidinize bazı çağrılar beklediğinizi, ancak aynı anda oluyorlar. Yani onların hangi sırayla aranacağını bilmenin bir yolu yok, ancak gerçekleşmesini beklediğiniz aramaların gerçekleştiğini bilmek istiyorsunuz (sıraya bakılmaksızın). Bunun gibi bir şey yapabilirsiniz:

var cq = new ConcurrentQueue<bool>();
mock.Setup(f => f.Bar(It.IsAny<bool>())).Callback<bool>(cq.Enqueue);
Parallel.Invoke(() => mock.Object.Bar(true), () => mock.Object.Bar(false));
Console.WriteLine("Invocations: " + String.Join(", ", cq));

// output:
// Invocations: True, False

BTW, yanıltıcı "önce Returns" ve "sonra Returns" ayrımı ile karıştırılmaz. Bu yalnızca, özel kodunuzun Returnsdeğerlendirildikten sonra mı yoksa daha önce mi çalışacağına ilişkin teknik bir ayrımdır . Arayanın gözünde, her ikisi de değer dönmeden önce çalışır. Nitekim, yöntem void-geri dönüyorsa , arayamazsınız bile Returnsve yine de aynı şekilde çalışır. Daha fazla bilgi için https://stackoverflow.com/a/28727099/67824 adresine bakın .


1

Buradaki diğer iyi cevapların yanı sıra, bir istisna atmadan önce mantığı gerçekleştirmek için kullandım. Örneğin, daha sonra doğrulama için bir yönteme iletilen tüm nesneleri depolamam ve bu yöntemin (bazı test durumlarında) bir istisna atması gerekiyordu. Arama .Throws(...)üzerinde Mock.Setup(...)geçersiz kılar Callback()eylem ve asla bunu çağırır. Bununla birlikte, Geri Arama içinde bir istisna atarak, geri aramanın sunduğu tüm iyi şeyleri yine de yapabilir ve yine de bir istisna atabilirsiniz.

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.