İmzasında isteğe bağlı bir bağımsız değişken olan bir yöntemi açıkça belirtmeden veya aşırı yük kullanmadan nasıl Moq yapabilirim?


119

Aşağıdaki arayüz göz önüne alındığında:

public interface IFoo
{
    bool Foo(string a, bool b = false);
}

Moq kullanarak alay etmeye çalışıyorum:

var mock = new Mock<IFoo>();
mock.Setup(mock => mock.Foo(It.IsAny<string>())).Returns(false);

derleme sırasında aşağıdaki hatayı verir:

Bir ifade ağacı, isteğe bağlı bağımsız değişkenler kullanan bir çağrı veya çağrı içeremez

Yukarıda belirtilen sorunu Moq'un sorunlar listesinde bir geliştirme olarak buldum ve 4.5 sürümüne atanmış gibi görünüyor (ne zaman olursa olsun).

Sorum şu: Yukarıdakilerin yakın zamanda düzeltilmeyeceği düşünülürse ne yapmalıyım? Seçeneklerim yalnızca, her alay ettiğimde isteğe bağlı parametrenin varsayılan değerini açıkça ayarlamak (bu, ilk etapta birini belirleme noktasını bozar) veya bool olmadan bir aşırı yükleme oluşturmak (benim yaptığım gibi) C # 4'ten önce)?

Ya da bu sorunun üstesinden gelmenin daha akıllıca bir yolunu bulan var mı?


5
İkinci parametre için sadece It.IsAny <bool> () belirtmek mantıklı olur mu?
Paul d'Aoust

Bir buçuk yıl sonra bu hala doğru ..
Mukus

@Mukus, bir PR bırakmaktan çekinmeyin kardeşim.
IamDOM

Yanıtlar:


91

Şu anda tek seçeneğinizin boolparametreyi kurulumuna açıkça dahil etmek olduğuna inanıyorum Foo.

Varsayılan bir değer belirleme amacını bozduğunu sanmıyorum. Varsayılan değer, kodu çağırmak için bir kolaylıktır, ancak testlerinizde açıkça belirtmeniz gerektiğini düşünüyorum. Diyelim ki boolparametreyi belirlemekten vazgeçebilirsiniz . Gelecekte, birisi varsayılan değerini değiştirirse ne olur bhiç true? Bu başarısız testler (ve haklı yani) yol açacaktır, ancak gizlendi varsayımın düzeltme daha zor olacaktır bolduğunu false. boolParametrenin açıkça belirtilmesinin başka bir faydası daha vardır: testlerinizin okunabilirliğini artırır. Bunlardan geçen biri Foo, iki parametreyi kabul eden bir işlev olduğunu çabucak anlayacaktır . Bu benim 2 sentim, en azından :)

Her dalga geçtiğinizde bunu belirtmeye gelince, kodu çoğaltmayın: bir işlevdeki taklidi oluşturun ve / veya başlatın, böylece yalnızca tek bir değişiklik noktasına sahip olursunuz. Gerçekten istiyorsanız, Moq'un Fooparametrelerini bu başlatma işlevine kopyalayarak Moq'un burada görünen eksikliğinin üstesinden gelebilirsiniz :

public void InitFooFuncOnFooMock(Mock<IFoo> fooMock, string a, bool b = false)
{
    if(!b)
    {
        fooMock.Setup(mock => mock.Foo(a, b)).Returns(false);
    }
    else
    {
        ...
    }
}

1
Mükemmel cevap; Ben zaten devam ettim ve bunu alaylarımda açıkça belirttim, ancak cevabınız çok açık ve mantıklı bir şekilde bunu neden bu şekilde yapmam gerektiğini doğruluyor. Teşekkürler @Chris.
Appulus

9
varsayılan bir parametrenin değiştirilmesi "gerekir" testleri bozmalıdır. Bir varsayılan değiştirildiğinde testlerin başarısız olmaması, kötü testin bir işareti olabilir. Kod varsayılanları kullanabilir ama testler kullanmıyor mu?
Pop Catalin

Bir süredir, ancak bu yaklaşımı Moq ile bir arayüzle (Dapper'da IDConnection) alay etmeye çalışırken denedim ve hala aynı hatayı alıyorum. Herhangi bir fikriniz neden? Örnek satır: mockDB.Setup (x => x.Query <MyObject> (It.IsAny <string> (), It.IsAny <DynamicParameters> (), It.IsAny <IDbTransaction> (), false, 600)). İade (yeni Liste <MyObject> ()); Son iki değer, kurduğum yöntemdeki isteğe bağlı parametrelerdir.
Raelshark

4
Arrgggh! The horrible if (!x) {} else {}anti-pattern :)
nicodemus13

1
@ nicodemus13 Evet, ancak kod örneğini sorudaki OP örneğine mümkün olduğunca yakın tutmaya çalışıyordum.
Chris Mantle

8

Bugün bu sorunla karşılaştığımız için Moq bu kullanım durumunu desteklemiyor. Öyleyse, yöntemi geçersiz kılmak bu durum için yeterli olacak gibi görünüyor.

public interface IFoo
{
    bool Foo(string a);

    bool Foo(string a, bool b);
}

Şimdi her iki yöntem de mevcuttur ve bu örnek işe yarar:

var mock = new Mock<IFoo>();
mock.Setup(mock => mock.Foo(It.IsAny<string>())).Returns(false);

2

Moq 4.10.1 sürümünü kullanarak aşağıdakileri yapabildim

Arayüz ile:

public interface IFoo
{
    bool Foo(string a, bool b = false);
}

Ve alay

var mock = new Mock<IFoo>();
mock.Setup(mock => mock.Foo(It.IsAny<string>(), It.IsAny<bool>())).Returns(false);

İlk parametre tamam ile Foo'ya yapılan bir çağrıyı çözer

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.