0

I am currently writing unit tests for a class that formats values based on parameters found in a big xml file.

The class I am testing receives another class in its constructor that provides functionality to parse and read the xml files. I think it is bad style to give the tested class a concrete instance of the xml reading class, because I believe doing so would result in testing the xml reading class every time I want to - in fact - test the formatting functions of the main class. All unit tests in the formatting class would fail if there was a problem in the xml reading class, which is clearly not the formatting class' fault.

So how should I proceed?

Obviously I would just create a mock of the xml reading class and pass that as an argument to the constructor. However the formatting class would use this instance to create about 5 private instances of other classes.

Because I don't know what these classes want to do (and honestly these tests should not care) I would like to mock away these private fields of the class I am testing.

Is that even ok to do? How would I do that using Moq?

-edit-

see the following example:

public class FormatterCore : IFormatterInterfaceIWantToTest
{
    public FormatterCore(IConfigService service)
    { 
      this.something = new SomeStuffA(service);
      this.somethingThatINeed = new SomethingUserfull(service);
      this.somethingElse = new SomeOtherStuff(service);
      this.somethingTotallyDifferent = new SomeReallyUselessStuff(service);
      //... 
    }    
    public T Format<T>(object input, string id)
    {
      // implementation of the interface I want to test
    }
}

In my example I want to test the method Format<T>() of the interface. To create an instance of the Formatter class, I'd need to pass an instance of a IConfigService implementation (which is expensive and cumbersome, because it would require different xml files and takes a while). My problem here is that I don't want to create an instance of the configService for every unit test because this would mean that I'd test the configService itself with every test in the FormatterCore unit.

buddybubble
  • 1,269
  • 14
  • 33
  • 1
    *However the formatting class would use this instance to create about 5 private instances of other classes.* Would be nice to see an example of that. – sloth Oct 17 '13 at 09:59
  • @DominicKexel I see, I edited my initial question – buddybubble Oct 17 '13 at 10:58

2 Answers2

1

In order to test FormatterCore you should not create an instance of a IConfigService implementation. You have to create and set up a mock object of IConfigService.

[TestClass]
public class FormatterCoreTest
{
    Mock<IConfigService> сonfigServiceMock;

    [TestInitialize]
    public void Init()
    {
        сonfigServiceMock = new Mock<IConfigService>();
    }

    [TestMethod]
    public void Format()
    {
        // arrange
        var input = /* input value */;
        var id = /* id value */;
        var сonfigServiceMock
            .Setup(services => services.YourMethodToMock())
            .Returnes(/* expected result or behaviour */);

        // act
        var target = new FormatterCore(сonfigServiceMock.Object);

        var result = target.Format</* AnyType */>(input, id);

        // assert
        /* Your asserts */
        result.Should().Be(/* expectred result */);
        Assert.AreEqual /* expectred result */, result);
    }
}

Are types SomeStuffA, SomethingUserfull, SomeOtherStuff and SomeReallyUselessStuff nested and can't be tested or public and it is possible?

If it is possible to test types SomeStuffA, SomethingUserfull, SomeOtherStuff and SomeReallyUselessStuff then it is better to inject their instances into constructor of FormatterCore instead of creating them in the constructor.

public class FormatterCore : IFormatterInterfaceIWantToTest
{
    ISomeStuffA something;
    ISomethingUserfull somethingThatINeed;
    ISomeOtherStuff somethingElse;
    ISomeReallyUselessStuff somethingTotallyDifferent;

    public FormatterCore(
        ISomeStuffA someStuffA,
        ISomethingUserfull somethingUserfull,
        ISomeOtherStuff someOtherStuff,
        ISomeReallyUselessStuff someReallyUselessStuff
        )
    {
        this.something = someStuffA;
        this.somethingThatINeed = somethingUserfull;
        this.somethingElse = someOtherStuff;
        this.somethingTotallyDifferent = someReallyUselessStuff;
        //... 
    }

    public T Format<T>(object input, string id)
    {
        // implementation of the interface I want to test
    }
}

Let your IoC be responsible for instance creation.

It will be needed to create and setup mocks for all dependencies in every test.

Ilya Palkin
  • 14,687
  • 2
  • 23
  • 36
0

As you can't access the private variables of the XML formatting class (other than hacking into the class by reflection), and you can't be certain of when the other classes are created, I don't think you can mock them in the way you'd like to. Having to hack into a class to access private variables or methods for testing is a code smell - it means you have hidden testable functionality that should be exposed.

So, to expose that functionality, it seems like your best course of action would be to inject factories that the XML formatting class uses to create these other classes. Your XML reader/parser mock would be passed to the Create methods, and you would return appropriate mocks of those classes for the XML formatting class to use.

Alternatively, you could treat the XML formatting class as you would in an integration test - accept that other classes will be created with your XML reader/parser mock as a parameter, and set up that mock to expect calls from them as well.

Chris Mantle
  • 6,595
  • 3
  • 34
  • 48
  • can you elaborate the part about injecting factories? If I understand you correctly this would require changes to the tested code to expose the creating of the internal fields. Afraid I can't do that. – buddybubble Oct 17 '13 at 11:01
  • Ah, if you can't change `FormatterCore`, then injecting factories isn't going to work. I'd recommend that you set up your `IConfigService` mock to expect calls from `SomeStuffA` and the others too. Think of `FormatterCore` and the classes it creates as a single unit. You could use reflection to set those private fields to other mocks ([as outlined here](http://stackoverflow.com/questions/10862747/access-private-fields), but figuring out the dependencies between those classes and setting up stub calls might be very tricky, depending on how they interact. – Chris Mantle Oct 17 '13 at 11:16