42

It came to my attention lately that you can unit test abstract base classes using Moq rather than creating a dummy class in test that implements the abstract base class. See How to use moq to test a concrete method in an abstract class? E.g. you can do:

public abstract class MyAbstractClass 
{
    public virtual void MyMethod()
    {
        // ...    
    }
}

[Test]
public void MyMethodTest()
{
    // Arrange            
    Mock<MyAbstractClass> mock = new Mock<MyAbstractClass>() { CallBase = true };

    // Act
    mock.Object.MyMethod();

    // Assert
    // ... 
}

Now I was wondering if there was a similar technique to allow me to test protected members without having to create a wrapper class. I.e. how do you test this method:

public class MyClassWithProtectedMethod
{
    protected void MyProtectedMethod()
    {

    }
}

I'm aware of the Moq.Protected namespace, however as far as I can see it only allows you to setup expectations with e.g.

mock.Protected().Setup("MyProtectedMethod").Verifiable();

I'm also aware that the obvious answer here is "don't test protected methods, only test public methods", however that's another debate! I just want to know if this is possible using Moq.

Update: below is how I would test this normally:

public class MyClassWithProtectedMethodTester : MyClassWithProtectedMethod
{
    public void MyProtectedMethod()
    {
        base.MyProtectedMethod();
    }
}

Thanks in advance.

3
  • Is this what you want? Commented Oct 10, 2011 at 16:14
  • Am really wondering why there is no .Returns(..) for the .Setup(...)- the link to the API doc seems to be broken and I have no VS around right now - you sure that there is no Return? - bzlms post seems to indicate that there is/used to be one... Commented Oct 10, 2011 at 16:14
  • @bzlm No, that's the same as what i've posted above, it lets you set up an expectation that the protected method is called. I want to actually execute the protected method from test. I.e. I want to change the accessibility of the protected method to public for testing purposes, which I can do with a wrapper class. Commented Oct 10, 2011 at 16:20

3 Answers 3

44

Another way in Moq to call protected member is the following template:

  1. In your class, with protected member mark your function as virtual. For example:

    public class ClassProtected
        {
            public string CallingFunction(Customer customer)
            {
                var firstName = ProtectedFunction(customer.FirstName);
                var lastName = ProtectedFunction(customer.LastName);
    
                return string.Format("{0}, {1}", lastName, firstName);
            }
    
            protected virtual string ProtectedFunction(string value)
            {
                return value.Replace("SAP", string.Empty);
            }
        }
    

Then in your unit test add reference to

 using Moq.Protected;

and in your unit test you can write the following:

    [TestFixture]
    public class TestClassProttected
    {
        [Test]
        public void all_bad_words_should_be_scrubbed()
        {
            //Arrange
            var mockCustomerNameFormatter = new Mock<ClassProtected>();

            mockCustomerNameFormatter.Protected()
                .Setup<string>("ProtectedFunction", ItExpr.IsAny<string>())
                .Returns("here can be any value")
                .Verifiable(); // you should call this function in any case. Without calling next Verify will not give you any benefit at all

            //Act
            mockCustomerNameFormatter.Object.CallingFunction(new Customer());

            //Assert
            mockCustomerNameFormatter.Verify();
        }
    }

Take note of ItExpr. It should be used instead of It. Another gotcha awaits you at Verifiable. I don't know why, but without calling to Verifiable Verify will not be called.

Sign up to request clarification or add additional context in comments.

2 Comments

I dont see where the "From" method is coming from ? mockCustomerNameFormatter.Object is of type "ClassProtected" and that class does not have a "From" method ? I am asuming it should be "CallingFunction" instead?
Sorry for typo. You are correct it should be CallingFunction instead of from. I'll correct my answer
12

For starters, there's no point in unit testing an abstract method. There's no implementation! You may want to unit test an impure abstract class, verifying that the abstract method was called:

[Test]
public void Do_WhenCalled_CallsMyAbstractMethod()
{
    var sutMock = new Mock<MyAbstractClass>() { CallBase = true };
    sutMock.Object.Do();
    sutMock.Verify(x => x.MyAbstractMethod());
}

public abstract class MyAbstractClass
{
    public void Do()
    {
        MyAbstractMethod();
    }

    public abstract void MyAbstractMethod();
}

Note that I set CallBase to turn this into a partial mock, in case Do was virtual. Otherwise Moq would have replaced the implementation of the Do method.

Using Protected() you could verify that a protected method was called in a similar manner.

When you create a mock with Moq or another library, the whole point is overriding implementation. Testing a protected method involves exposing existing implementation. That's not what Moq is designed to do. Protected() just gives you access (presumably through reflection, since it's string-based) to override protected members.

Either write a test descendant class with a method that calls your protected method, or use reflection in the unit test to call the protected method.

Or, better yet, don't test protected methods directly.

10 Comments

Good spot! Sorry I wrote the question in a hurry as I had a train to catch ;-) I've updated it now. I meant ofc for testing non-abstract methods on an abstract class.
The test descendant class approach is the one I've already been using, I was just interested to know if Moq had a way of doing this for me. The idea came from this question: stackoverflow.com/questions/7691796/…
@TonyLeeper: Not that I'm aware of. You could write a reflection helper that would allow you to access the protected method; that would be very short.
I'll accept this as the answer as it's more of a Moq specific answer, and the answer is that you can't. Thanks both.
If you are implementing a library, saying, a base class that provides functionality that is not intended to be public but definitely intended to be used by derived classes, you should be able to test it. And, BTW, protected is public for the inheritance hierarchy, and, for example, creating xml docs will generate a warning for not commented protected members.
|
7

You've already touched upon the "test the public API, not private" thought process, and you've also already mentioned the technique of inheriting from the class and then testing its protected members that way. Both of these are valid approaches.

Beneath it all, the simple truth is that you consider this implementation detail (as that's what a private or protected member is) important enough to test directly rather than indirectly via the public API that would use it. If it is this important, perhaps it's important enough to promote to its own class. (After all, if it's so important, perhaps it is a responsibility that MyAbstractClass should not have.) The instance of the class would be protected inside MyAbstractClass, so only the base and derived types would have access to the instance, but the class itself would be fully testable otherwise and usable elsewhere if that became a need.

abstract class MyAbstractClass 
{
     protected ImportantMethodDoer doer;
}

class ImportantMethodDoer
{
     public void Do() { }
}

Otherwise, you're left* to the approaches you've already identified.


*Moq may or may not provide some mechanism for getting at private or protected members, I cannot say, as I do not use that particular tool. My answer is more from an architectural standpoint.

2 Comments

Hi Anthony, I agree with you on all points, however the method in question is the Application_AcquireRequestState(object sender, EventArgs e) event handler in the global.asax.cs of an Asp.Net MVC web application. It's not part of my own codebase. I could mark the method as public but I would be doing so for the purpose of testing only.
I don't know if I fully agree with this. Let's say you have an abstract class that defines a protected method called DoWork. You inherit from the abstract class, but you cannot test that method because it's protected (without using reflection). The protected override DoWork is a public api.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.