Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fake an object in NSubstitute and ignore its method's internal implementation?

I'm new to NSubstitute and trying to fake an existing class named OrgDataWS. This class has a method named GetDataSet:

 public XmlElement GetDataSet(int token)
 {
        string perfLogMessage = string.Format("Org.GetDataSet: {0}", Guid.NewGuid().ToString());
        MultiMessagePerformanceCounter performanceCounter = MultiMessagePerformanceCounter.StartNew(perfLogMessage);
        XmlElement result = orgDataManager.GetDataSet(token);
        performanceCounter.Stop();

        return result;
 }

The following is my test methods:

 [TestMethod]
 public void GetDataSetTest()
 {
      var dataWSStub = Substitute.For<OrgDataWS>();

      var orgManagerStub = Substitute.For<OrgDataManager>();

      var document = new XmlDocument();
      var xmlElement = document.CreateElement("a");
      orgManagerStub.GetDataSet(Arg.Any<int>()).Returns<XmlElement>(xmlElement);


      dataWSStub.OrgDataManager = orgManagerStub;


      var result = dataWSStub.GetDataSet(99);
 }

However, when I run my test methods, this line

orgManagerStub.GetDataSet(Arg.Any<int>()).Returns<XmlElement>(xmlElement);

threw an exception. This exception is from the implementation of OrgDataManager class, from my understanding, this is not supposed to happen. The purpose of using that clause is that I hope if the orgManagerStub's DataDataSet method is invoked with any Int parameter, just return my xmlElement instance. I didn't hope my code to run the detailed implementation of OrgDataManager.

What's wrong with my test code? How to fix it?

like image 932
mkutkz Avatar asked Dec 11 '22 03:12

mkutkz


1 Answers

As per the documentation:

Warning: Substituting for classes can have some nasty side-effects. For starters, NSubstitute can only work with virtual members of the class, so any non-virtual code in the class will actually execute! If you try to substitute for your class that formats your hard drive in the constructor or in a non-virtual property setter then you’re asking for trouble. If possible, stick to substituting interfaces.

(my emphasis)

The declaration you showed is not virtual, so the solution is to either create an interface for it, and substitute for that, or at least make that method virtual (and possibly other methods as well).

like image 124
Lasse V. Karlsen Avatar answered Jan 18 '23 22:01

Lasse V. Karlsen