Yapıcı parametrelere sahip olduğunda Moq ile nesneleri alay etme


94

Moq kullanarak alay etmeye çalıştığım bir nesne var. Nesnenin yapıcısı gerekli parametrelere sahiptir:

public class CustomerSyncEngine {
    public CustomerSyncEngine(ILoggingProvider loggingProvider, 
                              ICrmProvider crmProvider, 
                              ICacheProvider cacheProvider) { ... }
}

Şimdi moq'un v3 "setup" veya v4 "Mock.Of" sözdizimini kullanarak bu nesne için bir model oluşturmaya çalışıyorum ama bunu çözemiyorum ... denediğim her şey doğrulamıyor. Şimdiye kadar elimde olan şey şu, ama son satır bana sahte değil gerçek bir nesne veriyor. Bunu yapmamın nedeni, CustomerSyncEngine üzerinde çağrılmakta olduğunu doğrulamak istediğim yöntemlerim olması ...

// setup
var mockCrm = Mock.Of<ICrmProvider>(x => x.GetPickLists() == crmPickLists);
var mockCache = Mock.Of<ICacheProvider>(x => x.GetPickLists() == cachePickLists);
var mockLogger = Mock.Of<ILoggingProvider>();

// need to mock the following, not create a real class like this...
var syncEngine = new CustomerSyncEngine(mockLogger, mockCrm, mockCache);

Çağrıldığını doğrulamak istediğiniz örnek bir yöntem sağlayabilir misiniz?
Ciaran

4
Dolayısıyla, Arabirimlerden ziyade Sınıflara bağımlılıklarım varsa, onların bağımlılıklarıyla bile dalga geçmem gerekir, bu yinelemeli olarak azalır. Sonunda, kodumdaki arayüzlere ihtiyacım olmasa bile, kodumu test edilebilir tutmak için bazı arayüzler kullanmaya zorlanıyorum. Bence çok fazla arayüz, somut derslerle alay etmekten daha büyük bir koku ...
Tarion

Yanıtlar:


34

Son satır size gerçek bir örnek veriyor çünkü yeni anahtar sözcüğü CustomerSyncEngine ile alay etmiyorsunuz.

Kullanmalısın Mock.Of<CustomerSyncEngine>()

Mocking Concrete türleriyle ilgili tek sorun, Moq'un genel bir varsayılan kurucuya (parametresiz) ihtiyaç duyması VEYA Moq'u yapıcı arg belirtimi ile oluşturmanız gerektiğidir. http://www.mockobjects.com/2007/04/test-smell-mocking-concrete-classes.html

Yapılacak en iyi şey, sınıfınıza sağ tıklayıp Arayüzü çıkar'ı seçmektir.


3
Sorunla ilgili olarak, bir alternatif bir AutoMocking konteyneri kullanmaktır. Benim favorim Machine.Fakes ile birlikte Machine.Fakes.Özellikler, otomatik kilitlenen bir konteyner kullanmak, daha küçük yüzey alanlarını test etmeyi kolaylaştırır. Andrew'un CustomerSyncEngine, yalnızca ICrmProvidergeleneksel alay uygulamalarıyla kullanımların 3 arabirimin tümü için sağlanması gerektiği, oysa autmocking kapsayıcısının yalnızca bir tane sağlamanıza izin verdiği bir yöntemi test etmesi gerektiğini varsayalım .
Chris Marisic

74

Son satırı şu şekilde değiştirin:

var syncEngine = new Mock<CustomerSyncEngine>(mockLogger, mockCrm, mockCache).Object;

ve çalışmalı


3
Bu yorumun cevabıma nasıl uygulanacağından emin değil misiniz?
Suhas

2
Çünkü bu, mockLogger ve diğerleri bir Object özelliğine sahip olmadıkları için bir istisna atacaklarından bir derleme hatasına neden olacaktır
Justin Pihony

2
OP, logger, crm ve cache türlerinin taklitlerini oluşturmak için Mock.Of <T> () kullandığından, döndürülen nesne Mock <T> olarak değil, T olarak döndürülür. Bu yüzden, MockLogger.Object vb.Müşteri Eşitleme Motorunun Mock'una verilirken gerekli değildir ve @JustinPihony'nin de bahsettiği gibi, size bir tasarım zamanı hatası göstermelidir.
Josh Gust

1
@suhas Onun olmamalınew Mock<CustomerSyncEngine>(new object[]{mockLogger, mockCrm, mockCache}).Object;
GiriB

@GiriB gerekli değil, ancak Params ile sahte tanımlandığı için mümkün. public Mock (params object [] args)
Jiří Herník
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.