Neden “Sanal olmayan (VB'de geçersiz kılınabilir) üye için geçersiz kurulum…” iletisi ile bir İstisna alıyorum?


176

Bir bool türü döndüren sanal olmayan bir yöntemle alay etmek zorunda birim testi var

public class XmlCupboardAccess
{
    public bool IsDataEntityInXmlCupboard(string dataId,
                                          out string nameInCupboard,
                                          out string refTypeInCupboard,
                                          string nameTemplate = null)
    {
        return IsDataEntityInXmlCupboard(_theDb, dataId, out nameInCupboard, out refTypeInCupboard, nameTemplate);
    }
}

XmlCupboardAccessSınıfta sahte bir nesne var ve aşağıda gösterildiği gibi benim test durumda bu yöntem için sahte kurmaya çalışıyorum

[TestMethod]
Public void Test()
{
    private string temp1;
    private string temp2;
    private Mock<XmlCupboardAccess> _xmlCupboardAccess = new Mock<XmlCupboardAccess>();
    _xmlCupboardAccess.Setup(x => x.IsDataEntityInXmlCupboard(It.IsAny<string>(), out temp1, out temp2, It.IsAny<string>())).Returns(false); 
    //exception is thrown by this line of code
}

Ama bu çizgi istisna atıyor

Invalid setup on a non-virtual (overridable in VB) member: 
x => x.IsDataEntityInXmlCupboard(It.IsAny<String>(), .temp1, .temp2, 
It.IsAny<String>())

Bu istisnayı nasıl aşacağınıza dair bir öneriniz var mı?


Testinizde neler var XmlCupboardAccess?
Preston Guillot

9
basit .. işaretlemeniz gerekiyor virtual. Adedi, geçersiz kılamayacağı somut bir tiple alay edemez.
Simon Whitehead

Yanıtlar:


265

Adedi sanal olmayan yöntemleri ve kapalı sınıfları alay edemez. MOQ nesnesini kullanarak bir test çalıştırırken, MOQ aslında "XmlCupboardAccess" öğenizden devralan ve "SetUp" yönteminde ayarladığınız davranışları geçersiz kılan bir bellek içi proxy türü oluşturur. Ve C # 'da bildiğiniz gibi, bir şeyi yalnızca sanal olarak işaretlenmişse geçersiz kılabilirsiniz, bu Java'da geçerli değildir. Java, statik olmayan her yöntemin varsayılan olarak sanal olduğunu varsayar.

Düşünmeniz gereken başka bir şey de "CupboardAccess" iniz için bir arayüz sunmak ve bunun yerine arayüz ile alay etmeye başlamak. Kodunuzu ayırmanıza ve daha uzun vadede faydalanmanıza yardımcı olur.

: Son olarak, gibi çerçeveler vardır Typemock ve JustMock olmayan sanal yöntemleri alay edebilir bu nedenle IL ile doğrudan çalışmaya ve. Ancak her ikisi de ticari ürünlerdir.


59
Sadece arayüzleri taklit etmeniz gerektiğinde +1. Bu soru karşılaştığım sorunu çözdü, çünkü altta yatan arayüzü değil, yanlışlıkla sınıfı alay ettim.
Paul Raff

1
Bu sadece sorunu çözmekle kalmaz, aynı zamanda teste ihtiyaç duyan tüm sınıflarınız için arayüzler kullanmak iyi bir uygulamadır. Moq aslında diğer alaycı çerçevelerden bazıları bu prensibi aşmanıza izin verdiği için iyi Bağımlılık Tersine sahip olmaya zorlar.
Xipooo

Sahte bir uygulamanız varsa, örneğin FakePeopleRepository, arayüzüm, örneğin, IPeopleRepository ve bu sahte uygulama ile alay edersem bu prensibin ihlali olarak kabul edilir miyim? Sanırım IoC hala korunuyor çünkü test kurulumumda sahte nesneyi kurucusundaki arabirimi alan hizmet sınıfıma geçirmem gerekiyor.
paz

1
@paz MOQ kullanmanın tüm amacı sahte uygulamalardan kaçınmaktır. Şimdi, sınır koşullarını vb. Kontrol etmek için sahte uygulamanın kaç varyantını düşünün. Teorik olarak, evet, sahte bir uygulamayı taklit edebilirsiniz. Ama pratikte bir kod kokusu gibi geliyor.
Amol

Bu hatanın aslında arabirimlerdeki kafa karıştırıcı olabilecek uzantı yöntemleriyle ortaya çıkabileceğini unutmayın.
Dan Pantry

34

Benimle aynı sorunu yaşayan herkese yardım olarak, arayüz yerine uygulama türünü yanlışlıkla yanlış yazdım.

var mockFileBrowser = new Mock<FileBrowser>();

onun yerine

var mockFileBrowser = new Mock<IFileBrowser>();


5

Alaycı sınıf yerine, o sınıf arayüzünü alay etmelisiniz. XmlCupboardAccess sınıfından arayüzü ayıkla

public interface IXmlCupboardAccess
{
    bool IsDataEntityInXmlCupboard(string dataId, out string nameInCupboard, out string refTypeInCupboard, string nameTemplate = null);
}

Ve yerine

private Mock<XmlCupboardAccess> _xmlCupboardAccess = new Mock<XmlCupboardAccess>();

değişmek

private Mock<IXmlCupboardAccess> _xmlCupboardAccess = new Mock<IXmlCupboardAccess>();

3

Bir arabirimin uzantı yönteminin çağrıldığını doğrularsanız bu hatayı da alırsınız.

Örneğin alay ediyorsanız:

var mockValidator = new Mock<IValidator<Foo>>();
mockValidator
  .Verify(validator => validator.ValidateAndThrow(foo, null));

Aynı istisnayı alacaksınız çünkü arayüzdeki .ValidateAndThrow()bir uzantı IValidator<T>.

public static void ValidateAndThrow<T>(this IValidator<T> validator, T instance, string ruleSet = null)...


-12

Kod:

private static void RegisterServices(IKernel kernel)
{
    Mock<IProductRepository> mock=new Mock<IProductRepository>();
    mock.Setup(x => x.Products).Returns(new List<Product>
    {
        new Product {Name = "Football", Price = 23},
        new Product {Name = "Surf board", Price = 179},
        new Product {Name = "Running shose", Price = 95}
    });

    kernel.Bind<IProductRepository>().ToConstant(mock.Object);
}        

ancak istisnaya bakın.


4
Çözümünüzün bir açıklamasını verebilir misiniz? Ayrıca, "istisnayı görün ..." asılı kalır. biraz daha açıklayabilir misin?
amadan
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.