4

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?

Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
mkutkz
  • 99
  • 2
  • 8

1 Answers1

13

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).

Lasse V. Karlsen
  • 380,855
  • 102
  • 628
  • 825
  • I understand your point. Actually I do have an interface for the class. However, from my point of view, I'm trying to test the implementation, or I want to make sure that the "orgDataManager"'s DataDataSet method was invoked. However, I can't define a property in the interface, which means i can't tell the object mocked from the interface to return my pre-defined XmlElement instance when it's "orgDataManager" object's GetDataSet method is invoked. – mkutkz Aug 25 '14 at 07:36
  • Well, i see how to test. I need to test the manager, not the OrgDataWS. – mkutkz Aug 25 '14 at 07:38
  • The important part here is **substitute**, unless you give NSubstitute a method to do the substitution, it can't do its job. – Lasse V. Karlsen Aug 25 '14 at 10:20