40

I was recently discussing with some friends which of the following 2 methods is best to stub return results or calls to methods inside same class from methods inside same class.

This is a very simplified example. In reality the functions are much more complex.

Example:

public class MyClass
{
     public bool FunctionA()
     {
         return FunctionB() % 2 == 0;
     }

     protected int FunctionB()
     {
         return new Random().Next();
     }
}

So to test this we have 2 methods.

Method 1: Use Functions and Actions to replace functionality of the methods. Example:

public class MyClass
{
     public Func<int> FunctionB { get; set; }

     public MyClass()
     {
         FunctionB = FunctionBImpl;
     }

     public bool FunctionA()
     {
         return FunctionB() % 2 == 0;
     }

     protected int FunctionBImpl()
     {
         return new Random().Next();
     }
}

[TestClass]
public class MyClassTests
{
    private MyClass _subject;

    [TestInitialize]
    public void Initialize()
    {
        _subject = new MyClass();
    }

    [TestMethod]
    public void FunctionA_WhenNumberIsOdd_ReturnsTrue()
    {
        _subject.FunctionB = () => 1;

        var result = _subject.FunctionA();

        Assert.IsFalse(result);
    }
}

Method 2: Make members virtual, derive class and in derived class use Functions and Actions to replace functionality Example:

public class MyClass
{     
     public bool FunctionA()
     {
         return FunctionB() % 2 == 0;
     }

     protected virtual int FunctionB()
     {
         return new Random().Next();
     }
}

public class TestableMyClass
{
     public Func<int> FunctionBFunc { get; set; }

     public MyClass()
     {
         FunctionBFunc = base.FunctionB;
     }

     protected override int FunctionB()
     {
         return FunctionBFunc();
     }
}

[TestClass]
public class MyClassTests
{
    private TestableMyClass _subject;

    [TestInitialize]
    public void Initialize()
    {
        _subject = new TestableMyClass();
    }

    [TestMethod]
    public void FunctionA_WhenNumberIsOdd_ReturnsTrue()
    {
        _subject.FunctionBFunc = () => 1;

        var result = _subject.FunctionA();

        Assert.IsFalse(result);
    }
}

I want to know wich is better and also WHY ?

Update: NOTE: FunctionB can also be public

6
  • Your example is simple, but not exactly correct. FunctionA returns a bool but only sets a local variable x and doesn't return anything.
    – Eric P.
    Feb 26, 2013 at 16:41
  • 1
    In this particular example, FunctionB can be public static but in a different class.
    – Leonid
    Feb 26, 2013 at 19:27
  • For Code Review, you are expected to post actual code not a simplified version of it. See the FAQ. As its stands, you are asking a specific question not looking for a code review. Feb 27, 2013 at 16:28
  • 1
    FunctionB is broken-by-design. new Random().Next() is almost always wrong. You should inject the instance of Random. (Random is also a badly designed class, which can cause a few additional problems) Feb 27, 2013 at 16:51
  • on a more general note DI via delegates is absolutely fine imho
    – jk.
    Feb 28, 2013 at 7:41

5 Answers 5

36

Edited following original poster update.

Disclaimer : not a C# programmer (mostly Java or Ruby). My answer would be : I would not test it at all, and I do not think you should.

The longer version is : private/protected methods are not parts of the API, they are basically implementation choices, that you can decide to review, update or throw away completely without any impact on the outside.

I suppose you have a test on FunctionA(), which is the part of the class that is visible from the external world. It should be the only one that has a contract to implement (and that could be tested). Your private/protected method has no contract to fulfil and/or test.

See a related discussion there : https://stackoverflow.com/questions/105007/should-i-test-private-methods-or-only-public-ones

Following the comment, if FunctionB is public, I'll simply test both using unit test. You may think that the test of FunctionA is not totally "unit" (as it call FunctionB), but I would not be too worried by that : if FunctionB test works but not FunctionA test, it means clearly that the problem is not in the subdomain of FunctionB, which is good enough for me as a discriminator.

If you really want to be able to totally separate the two tests, I would use some kind of mocking technique to mock FunctionB when testing FunctionA (typically, return a fixed known correct value). I lack the C# ecosystem knowledge to advice a specific mocking library, but you may look at this question.

7
  • 2
    Completely agree with @Martin answer. When you write unit tests for class you should not test methods. What you're testing is a class behavior, that the contract (the declaration what class is supposed to do) is satisfied. So, your unit tests should cover all the requirements exposed for this class (using public methods/properties), including exceptional cases
    – almaz
    Feb 26, 2013 at 16:29
  • Hello, thanks for the response, but it didn't answer my question. I doesn't matter if FunctionB was private / protected. It can also be public and still be called from FunctionA.
    – tranceru1
    Feb 26, 2013 at 16:32
  • The most common way to handle this problem, without redesigning the base class, is to subclass MyClass and override the method with the functionality you want to stub. It might also be a good idea to update your question to include that FunctionB could be public.
    – Eric P.
    Feb 26, 2013 at 16:50
  • 1
    protected methods are part of the public surface of a class, unless you ensure that there can be no implementations of your class in different assemblies. Feb 27, 2013 at 17:07
  • 2
    The fact that FunctionA calls FunctionB is an irrelevant detail from a unit testing perspective. If the tests for FunctionA are written correctly, it is an implementation detail that could be refactored-out later without breaking tests (so long as the overall behavior of FunctionA is left unchanged). The real issue is that FunctionB's retrieval of a random number needs to be done with an injected object, so that you can use a mock during testing to ensure that a well-known number is returned. This allows you test well-known inputs/outputs.
    – Dan Lyons
    Feb 27, 2013 at 18:27
11

I subscribe to the theory that if a function is important to test, or is important to replace, it is important enough to not be a private implementation detail of the class under test, but to be a public implementation detail of a different class.

So if I am in a scenario where I have

class A 
{
     public B C()
     {
         D();
     }

     private E D();
     {
         // i actually want to control what this produces when I test C()
         // or this is important enough to test on its own
         // and, typically, both of the above
     }
}

Then I am going to refactor.

class A 
{
     ICollaborator collaborator;

     public A(ICollaborator collaborator)
     {
         this.collaborator = collaborator;
     }

     public B C()
     {
         collaborator.D();
     }
}

Now I have a scenario where D() is independently testable, and fully replaceable.

As a means of organization, my collaborator might not live at the same namespace level. For example, if A is in FooCorp.BLL, then my collaborator might be another layer deep, as in FooCorp.BLL.Collaborators (or whatever name is appropriate). My collaborator might further only be visible inside the assembly via the internal access modifier, which I would then also expose to my unit testing project(s) via the InternalsVisibleTo assembly attribute. The takeaway is that you can still keep your API clean, as far as callers are concerned, while producing verifiable code.

2
  • Yes if ICollaborator needs several methods. If you have an object who's only job is to wrap a single method I'd rather see it replaced with a delegate though.
    – jk.
    Feb 28, 2013 at 7:39
  • You'd have to decide if a named delegate make sense or if an interface makes sense, and I won't decide for you. Personally, I am not averse to single (public) method classes. The smaller the better, as they become increasingly easy to understand. Feb 28, 2013 at 16:34
0

Adding on to what Martin points out,

If your method is private/protected - do not test it. It is internal to the class and should not be accessed outside the class.

In both the approaches that you mention, I have these concerns -

Method 1 - This actually changes the class under test's behaviour in the test.

Method 2 - This actually does not test the production code, instead tests another implementation.

In the problem stated, I see that the only logic of A is to see if the output of FunctionB is even. Although illustrative, FunctionB gives Random value, which is tough to test.

I expect a realistic scenario where we can setup MyClass such that we know what FunctionB would return. Then our expected result is known, we can call FunctionA and assert on the actual result.

4
  • 3
    protected is almost the same as public. Only private and internal are implementation details. Feb 27, 2013 at 17:08
  • @codeinchaos - I am curious here. For a test, protected methods are 'private' unless you modify assembly attributes. Only derived types have access to protected members. With the exception of virtual, I don't see why protected should be treated similar to public from a test. could you elaborate please? Feb 28, 2013 at 1:37
  • Since those derived classes can be in different assemblies, they're exposed to third party code, and thus part of the public surface of your class. To test them, you can either make them internal protected, use a private reflection helper, or create a derived class in your test project. Feb 28, 2013 at 8:21
  • @CodesInChaos, agreed that derived class can be in different assemblies, but the scope is still restricted to the base and derived types. Modifying the access modifier just to make it testable is something that I am a bit nervous about. I have done it, but it seems to be an antipattern to me. Feb 28, 2013 at 8:25
0

I personally use Method1 i.e. making all methods into Actions or Funcs as this has hugely improved code testability for me. As with any solution there are pros and cons with this approach:

Pros

  1. Allows for simple code structure where using Code Patterns just for Unit Testing might add additional complexity.
  2. Allows classes to be sealed and for the elimination of virtual methods that are required by popular mocking frameworks like Moq. Sealing classes and eliminating virtual methods makes them candidates for inlining and other compiler optimizations. (https://msdn.microsoft.com/en-us/library/ff647802.aspx)
  3. Simplifies testability as replacing the Func/Action implementation in a Unit test is as simple as just assigning a new value to the Func/Action
  4. Also allows for testing if a static Func was called from another method since static methods can not be mocked.
  5. Easy to refactor existing methods to Funcs/Actions since the syntax for calling a method on the call site remains the same. (For times when you can't refactor a method into a Func/Action see cons)

Cons

  1. Funcs/Actions can't be used if your class can be derived as Funcs/Actions have no inheritance paths like Methods
  2. Can't use default parameters. Creating a Func with default parameters entails creating a new delegate which might make the code confusing depending on the use case
  3. Can't use the named parameter syntax for calling methods like something(firstName: "S", lastName: "K")
  4. The biggest Con is that you don't have access to the 'this' reference in Funcs and Actions, and so any dependencies on the class must be explicitly passed in as parameters. Its good as you know all dependencies but bad if you have many properties that your Func will depend on. Your mileage will vary based on your use case.

So to sum up, using Funcs and Actions for Unit test is great if you know that your classes are never going to be overridden.

Also, I usually don't create properties for Funcs but inline them directly as such

public class MyClass
{
     public Func<int> FunctionB = () => new Random().Next();

     public bool FunctionA()
     {
         return FunctionB() % 2 == 0;
     }
}

Hope this helps!

-1

Using Mock its possible. Nuget : https://www.nuget.org/packages/moq/

And believe me its fairly simple and makes sense.

public class SomeClass
{
    public SomeClass(int a) { }

    public void A()
    {
        B();
    }

    public virtual void B()
    {

    }
}

[TestFixture]
public class Test
{
    [Test]
    public void Test_A_Calls_B()
    {
        var mockedObject = new Mock<SomeClass>(5); // You can also specify constructor arguments.
        //You can also setup what a function can return.
        var obj = mockedObject.Object;
        obj.A();

        Mock.Get(obj).Verify(x=>x.B(),Times.AtLeastOnce);//This test passes
    }
}

Mock needs method virtual to override.

Not the answer you're looking for? Browse other questions tagged or ask your own question.