1

I'm new to unit testing and I'd like to know how is this, I guess typical, problem usually solved:
I have protected method that I'd like to test. I've overriden the tested class with the test class, but the tested class has constructor with 4 arguments and no default constructor. In which part of the test class you add a call to the base (4 args) constructor? I've tried in [SetUp] method but I get Use of keyword 'base' is not valid in this context error.

I thought that this simple case is self explaining, but here's the example:

public class A
{
    protected Class1 obj1;
    protected Class2 obj2; 
    protected Class3 obj3; 
    protected Class4 obj4;

    public A(Class1 obj1, Class2 obj2, Class3 obj3, Class4 obj4)
    {
        this.obj1 = obj1;
        this.obj2 = obj2;
        this.obj3 = obj3;
        this.obj4 = obj4;
    }

    protected virtual void MethodA()
    {
        //some logic
    }
}

[TestFixture]
public class ATests : A
{
    [SetUp]
    public void SetUp()
    {            
        this.obj1 = Substitute.For<Class1>();
        this.obj2 = Substitute.For<Class2>();
        this.obj3 = Substitute.For<Class3>();
        this.obj4 = Substitute.For<Class4>();
        //this line below doesn't compile with the `Use of keyword 'base' is not valid in this context` error.
        base(obj1, obj2, obj3, obj4);
    }

    [Test]
    public void MethodA_test()
    {
        //test MethodA logic
    }
}
dragan.stepanovic
  • 2,955
  • 8
  • 37
  • 66
  • 1
    Please provide some code to demonstrate your problem. – dav_i Aug 12 '14 at 10:28
  • Another question that might interest you http://stackoverflow.com/questions/5601730/should-private-protected-methods-be-under-unit-test – Bryan Aug 12 '14 at 11:39

2 Answers2

1

ATests shouldn't inherit from A.

Simply change your test class definition to

[TestFixture]
public class ATests
{

and then instead of

base(obj1, obj2, obj3, obj4);

do something like

this.globalA = new A(obj1, obj2, obj3, obj4);

where globalA is a private field of type A which you can use in your test.


To access the protected method, you can add your test project as a friend assembly to your main project and mark your protected method as protected internal.

dav_i
  • 27,509
  • 17
  • 104
  • 136
  • but how to call protected A.MethodA? – dragan.stepanovic Aug 12 '14 at 11:47
  • 1
    @kobac See my comment above, you shouldn't be testing a protected (or private) methods. You should be testing functionality. This can be done in full using just public members. – Bryan Aug 12 '14 at 11:50
  • @Bryan I don't subscribe to that - it often makes a lot of sense to test methods which are hidden to the public, limiting yourself to just public methods for ideological reasons seems silly. – dav_i Aug 12 '14 at 11:54
  • @dav_i Each to their own I guess, I don't really see it as being for ideological reasons though, unit testing is about ensuring the interface presented by the class works correctly. Private/Protected methods are often refactored, which would likely break your unit tests. As long as the public members test successfully, it's implied that your private/protected members function correctly. – Bryan Aug 12 '14 at 12:01
  • 2
    @dav_i: The so-called *public* will only call public methods on your components. Your components will only call public methods on other components. Public contract is the only thing that's ever going to be called. Other than misfortunate design decision, low quality legacy code or bizzare 3rd party requirements, you'll never have to test anything other than public contract. – k.m Aug 12 '14 at 12:05
  • 1
    @jimmy_keen Consider the case where you produce a framework with a `public abstract class`, which you intend the client to inherit, with `protected` methods within, which obviously can be called in the derived class. These `protected` methods are still part of the contract with your client and therefore require testing as much as actual `public` methods. – dav_i Aug 12 '14 at 12:09
  • @dav_i Are those protected methods in an abstract class not accessed via a public method in the derived class? – Bryan Aug 12 '14 at 12:12
  • @Bryan You have no way of knowing what the client will do. – dav_i Aug 12 '14 at 12:13
  • @dav_i Sorry, I retract that last comment, I completely read past the part about a framework which a client inherits. – Bryan Aug 12 '14 at 12:14
  • @Bryan No worries. We're not really ever going to settle this in a comment thread on a SO answer anyway! The point is that you _can_ do this if you _choose_ and the .NET framework actively supports it using Friend Assemblies. – dav_i Aug 12 '14 at 12:17
  • Can you elaborate why I shouldn't inherit tested class when writing test class where I'm testing protected method? I saw some other answers on SO where this is a recommended approach. E.g. http://stackoverflow.com/a/13416253/25140 – dragan.stepanovic Aug 12 '14 at 13:41
  • @kobac Certainly you can inherit from a class in your tests, but that class shouldn't actually _be_ your test fixture. – dav_i Aug 12 '14 at 13:44
  • @dav_i didn't quite get it. I have a class with protected method, I'd like to test. In order to test it, one solution is to inherit the given test class in order to able to call the protected method I'd like to test. Is there a drawback of this approach? Also, is there a workaround for the problem i've explained in my question, with this kind of approach? – dragan.stepanovic Aug 12 '14 at 13:55
  • @dav_i: By doing so you are testing code that might never be called/used. This is highly defensive approach **but** not that uncommon when developing framework libraries. Point is, you still don't have to test that protected method itself but rather derived mockup exposing this method as public. – k.m Aug 14 '14 at 06:57
1

Common and easy approach is to create class deriving from A which will expose protected members you want to test:

public class TestableA : A
{
    public void TestableMethodA() 
    {
        base.MethodA();
    }
}

Now, your test fixture will excercise TestableA instead. You don't actually derive test fixture from A, you simply use the new derived, test-only class in your test:

[TestFixture]
public void ATests
{
    [Test]
    public void MethodA_DoesSomethingImportant()
    {
        var testedComponent = new TestableA();
        testedComponent.TestableMethodA();
        // verify 
    }
}

The drawback of this approach is the need to create extra type for testing purposes only. This can be mitigated by mocking frameworks usage (and using mock calling base implementation). Changing methods visibility purely for unit tests purpose should be the last resort when everything other fails or ends up being to expensive.

k.m
  • 30,794
  • 10
  • 62
  • 86