मैं ForPartsOf<...>() और फिर subst.Configure().MyMethod(...).Returns(...) या subst.When(x => x.MyMethod(..)).Returns(...) का उपयोग करके एक विधि को प्रतिस्थापित करने का प्रयास कर रहा हूं, लेकिन दोनों ही मामलों में वास्तविक MyMethod को कॉल किया जाता है। मैं इस धारणा के तहत था कि Configure() और When() दोनों को यह सुनिश्चित करना था कि MyMethod() कॉल "कॉन्फ़िगर मोड" में किया गया था, ताकि कोई वास्तविक कॉल न हो। क्या मै गलत हु? या मुझ से कुछ गलत हो रहा है?

यहाँ नीचे एक मेरा (बहुत सरलीकृत, और नाम बदला हुआ) कोड है। subst1 और subst2 दोनों के लिए, वास्तविक NeedsMoreWork विधि को item == null के साथ कॉल किया जाता है।

public interface IMyClass
{
    bool NeedsMoreWork(Item item, out Part part);
    bool DoWork(Item item);
}

public class MyClass : IMyClass
{
    private ILogger log;

    public MyClass(ILogger log)
    {
        this.log = log;
    }

    public bool NeedsMoreWork(Item item, out Part part)
    {
        log.Debug($"Examining item {item.Id}");
        part = null;
        if (item.Completed())
        {
            log.Debug($"Item {item.Id} already completed.");
            return false;
        }
        part = item.GetNextPart();
        log.Debug($"Item {item.Id} needs work on part {part.Id}.");
        return true;            
    }

    public bool DoWork(Item item)
    {
        if (!item.NeedsMoreWork(item, out Part part))
            return false;
        log.Debug($"Starting work on part {part.Id}.");
        // Do work on part.
        log.Debug($"Work completed on part {part.Id}.");
        return true;
    }
}

[TestMethod]
public void TestDoWork()
{
    // Version with Configure():
    var subst1 = Substitute.ForPartsOf<MyClass>(Substitute.For<ILogger>());
    subst1.Configure()
        .NeedsMoreWork(Arg.Any<Item>(), out Arg.Any<Part>())
        .Returns(false);

    // Version with WhenForAnyArgs():
    var subst2 = Substitute.ForPartsOf<MyClass>(Substitute.For<ILogger>());
    subst2.WhenForAnyArgs(x => x.NeedsMoreWork(Arg.Any<Item>(), out Arg.Any<Part>())
        .Returns(false);
}
1
Kjell Rilbe 18 सितंबर 2019, 19:06

1 उत्तर

सबसे बढ़िया उत्तर

NSubstitute का उपयोग करते समय, उपहासित/स्टब किए जाने वाले सदस्यों को ओवरराइड करने के लिए virtual होना चाहिए।

संदर्भ आंशिक सदस्य और परीक्षण जासूस

public class MyClass : IMyClass {
    private readonly ILogger log;

    public MyClass(ILogger log) {
        this.log = log;
    }

    public virtual bool NeedsMoreWork(Item item, out Part part) { //<-- THIS IS NOW VIRTUAL
        log.Debug($"Examining item {item.Id}");
        part = null;
        if (item.Completed()) {
            log.Debug($"Item {item.Id} already completed.");
            return false;
        }
        part = item.GetNextPart();
        log.Debug($"Item {item.Id} needs work on part {part.Id}.");
        return true;            
    }

    public bool DoWork(Item item) {
        if (!NeedsMoreWork(item, out Part part))
            return false;
        log.Debug($"Starting work on part {part.Id}.");
        // Do work on part.
        log.Debug($"Work completed on part {part.Id}.");
        return true;
    }
}

NeedsMoreWork को अब आवश्यकतानुसार स्टब किया जा सकता है

[TestMethod]
public void TestDoWork_Should_Return_False() {
    //Arrange
    var subject = Substitute.ForPartsOf<MyClass>(Substitute.For<ILogger>());
    bool expected = false;
    subject.Configure().NeedsMoreWork(Arg.Any<Item>(), out Arg.Any<Part>()).Returns(expected);

    //Act
    bool actual = subject.DoWork(new Item());

    //Assert - FluentAssertions
    actual.Should().Be(expected);
}

सावधानी टिप्पणी पर ध्यान दें। यदि हमने .NeedsMoreWork(...) से पहले यहां Configure() का उपयोग नहीं किया होता तो व्यवहार को ओवरराइड करने का मौका मिलने से पहले वास्तविक विधि निष्पादित हो जाती। कुछ मामलों में यह कोई समस्या नहीं हो सकती है, लेकिन यदि संदेह है तो सुनिश्चित करें कि आप पहले Configure() पर कॉल करते हैं, इसलिए NSubstitute को पता है कि आप कॉल को कॉन्फ़िगर कर रहे हैं और कोई वास्तविक कोड नहीं चलाना चाहते हैं। (यह अभी भी गारंटी नहीं देता है कि वास्तविक कोड नहीं चलेगा - याद रखें, NSubstitute गैर-वर्चुअल कॉल को निष्पादित होने से नहीं रोकेगा।)

Configure() विधि केवल NSubstitute 4.0 और इसके बाद के संस्करण में उपलब्ध है। 4.0 से पहले के सत्यापन के लिए हमें When .. DoNotCallBase का उपयोग करने की आवश्यकता है

नोट: मेरा जोर

5
Community 20 जून 2020, 09:12