1

I'm currently working on a .NET 5.0 application.

I need to unit test an abstract base class, which implements a protected property protected IMediator Mediator.

My class looks like this:

public abstract class MyControllerBase : Controller
{
    protected IMediator Mediator { get; }

    protected MyControllerBase(IMediator mediator)
    {
       Mediator = mediator;
    }
}

My unit test looks like this:

[Fact]
[Trait(nameof(TestTraitName.Category), nameof(TestType.Unit))]
public void MyControllerTests()
{
    var testController = new TestController(new Mediator(Mock.Of<ServiceFactory>()));

    Assert.NotNull(anotherAuthController.TestMediator);
 }
}

 public class TestController : MyControllerBase
{
   public IMediator TestMediator { get; set; }

   public AnotherController(IMediator mediator)
   : base(mediator)
   {
      TestMediator = mediator;
   }
}

When I run my unit tests, unfortunately the protected property isn't covered by my tests.

Do you know, what is the correct way to unit test a protected property from an abstract base class in C#?

Do you know how to solve this issue?

azzurro123
  • 521
  • 2
  • 10
  • 19
  • I don't recommend you to test private and protected fields(methods). You should test only public methods. Anyway if you are interested in it, here is the answer https://stackoverflow.com/questions/11565560/what-are-the-good-practice-to-test-inject-private-field-in-c-sharp – Svyatoslav Ryumkin Mar 02 '21 at 11:56
  • This appears to be an [XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). – Nkosi Mar 02 '21 at 12:04
  • In this case I would suggest having the public property expose the base property `public IMediator TestMediator => base.Mediator;` – Nkosi Mar 02 '21 at 12:07
  • There are constrained and unconstrained isolation frameworks. The former - Moq, NSubstitute, FakeItEasy - allow you to mock only virtual members. You should use the latter, such as TypeMock, JustMock, MS Fakes (all paid) or free counterparts: Prig, Ionad.Fody, Pose, Harmony, MethodRedirect (google them) - they can mock static, private, etc members. – Alexander Petrov Mar 02 '21 at 12:13

2 Answers2

1

In this case I would suggest having the public property expose the base property

public class TestController : MyControllerBase {
    public IMediator TestMediator => base.Mediator;

    public TestController(IMediator mediator) : base(mediator) {
      
    }
}

[Fact]
[Trait(nameof(TestTraitName.Category), nameof(TestType.Unit))]
public void MyControllerTests() {
    var testController = new TestController(Mock.Of<IMediator>());    
    Assert.NotNull(testController.TestMediator);
}
Nkosi
  • 235,767
  • 35
  • 427
  • 472
0

Try this. For me this works with NSubtitute for protected properties.

public abstract class MyControllerBase : Controller
{
    protected virtual IMediator Mediator { get; }

    protected MyControllerBase(IMediator mediator)
    {
       Mediator = mediator;
    }
}

public class MyControllerBaseWrapper : MyControllerBase {
    protected override IMediator Mediator => base.Mediator;

    public MyControllerBaseWrapper(IMediator mediator) : base(mediator)
    {
      
    }
    
    public IMediator GetMediator()
    {
       return Mediator;
    }

}

[Fact]
[Trait(nameof(TestTraitName.Category), nameof(TestType.Unit))]
public void MyControllerTests() {
    var expectedValue = Substitute.For<IMediator>();
    var testController = Substitute.For<MyControllerBaseWrapper>(expectedValue);
    testController.GetType().GetProperty("Mediator", BindingFlags.NonPublic | BindingFlags.Instance)
            .GetValue(testController, null).Returns(expectedValue);

    Assert.EreEqual(expectedValue,testController.GetMediator());
}

Here I have used reflection for sub protected properties.

testController.GetType().GetProperty("Mediator", BindingFlags.NonPublic | BindingFlags.Instance)
                .GetValue(testController, null).Returns(expectedValue);