C# Xunit and Moq - Mock One Method Of Class And Also Call Other Real Base Class Method

Viewed 749

I'm coming from Java where I do this type of thing easily with Spies and Mockito. I realize Moq doesn't support Spies, but only mocking one of the methods in a class while calling other real methods seems doable by the documentation if you set CallBase.

Legacy class newly under test, trying to test the Split() method. Refactored the explicit filestream creation from inside the using in the Split method to its own GetReaderStream method so I could mock it (I started out protected, but I made it public to rule out Moq Protected setup issues as I learn).

public class MySplitter
{
  protected string _fileToSplit;
  protected string _outputFolder;

  public MySplitter(string fileToSplit, string outputFolder)
  {
    _fileToSplit = fileToSplit;
    _outputFolder = outputFolder;
  }
  
  public int Split()
  {
      int numberProcessed = 0;
      using (Stream streamToSplit = GetReaderStream())
      {
        // omit for brevity the logic we're trying to test
        numberProcessed++;
      }
      return numberProcessed;
  }
  
  public Stream GetReaderStream()
  {
    return new FileStream(_fileToSplit, FileMode.Open, FileAccess.Read);
  }
}

Attempting to mock the GetReaderStream function to have the unit test use a text file from a ResourceStream rather than calling the filesystem FileStream.

    [Fact]
    public void Split_Test()
    {
      var mockSplitter = new Mock<MySplitter>(It.IsAny<string>(), It.IsAny<string>());
      mockSplitter.CallBase = true;

      var assembly = Assembly.GetExecutingAssembly();
      string resource = "MyNameSpace.Tests.Resources.SPLITTABLE_TEST_FILE_07.DAT";
      using (Stream stream = assembly.GetManifestResourceStream(resource))
      {
        mockSplitter.Setup(m => m.GetReaderStream()).Returns(stream);
        int numberOfFiles = mockSplitter.Object.Split();
        Assert.Equal(7, numberOfFiles);
      }
    }

Sadly my Moq Setup is failing and Exception thrown: 'System.NotSupportedException' in Moq.dll isn't helping me determine which aspect of my Setup is not supported.

I've confirmed that my stream is being populated successfully from the resource file and is not null when it is specified as the expected return value in the Setup line.

Any direction, remedial Moq help, or "you can't get there from here" advice would be appreciated.

1 Answers

rgvlee has the right of it in the comment, and I would have accepted that answer. Since this is my first SO question I'm not sure, but it appears I cannot mark a comment as an accepted answer.

The takeaway, I believe is that methods in java are virtual by default, so that is why mockito has been happy all these years. Once I marked GetReaderStream() as virtual in C#, Moq worked fine, and I was even able to change it back to protected instead of public and tweak the setup syntax in the test.

Related