Unit Testing When SUT Has Protected Methods

Updated 18/09/2024

I have a custom AuthorizeAttribute called FooAttribute, this is my SUT (software under test) and its core implementation is not important for this post but the fact that the base class AuthorizeAttribute has protected virtual keywords before the method IsAuthorized is.

1
2
protected virtual bool IsAuthorized(HttpActionContext actionContext)
{ ... }

So the custom FooAttribute looks something like this, it has some logic in IsAuthorized that I want to unit test because its important that this code behaves as expected and doesnt change.

1
2
3
4
5
6
7
public class FooAttribute : AuthorizeAttribute
{
...
protected override bool IsAuthorized(HttpActionContext context)
{
// please unit test me
...

The noob would just try something like the below but this would protest as FooAttribute.IsAuthorized(HttpActionContext) is inaccessible due to its protection level, which is to be expected 🐒

1
2
3
4
5
6
7
8
9
[Fact]
public void IsAuthorized_GivenWhenThen()
{
// Arrange
var classUnderTest = new FooAttribute(_scope);

// Act
var actual = classUnderTest.IsAuthorized(_context); // <-- wont compile
}

Work Around

A work around is just to add some additional setup to expose ‘protected’ behaviour in the test.

  1. Add the additional setup ExposedFooAttribute to the test class file
1
2
3
4
5
6
7
8
9
10
11
12
/// <summary>
/// Additional setup required to expose 'protected' behaviour
/// </summary>
public class ExposedFooAttribute : FooAttribute
{
public ExposedFooAttribute(string scope) : base(scope) { }

public bool ExposedIsAuthorized(HttpActionContext context)
{
return IsAuthorized(context);
}
}
  1. Change the noob test above to use the exposed method as the entry point
1
2
3
4
5
6
7
8
public void IsAuthorized_GivenWhenThen()
{
// Arrange
var classUnderTest = new ExposedFooAttribute(_scope);

// Act
var actual = classUnderTest.ExposedIsAuthorized(_context); // this will compile
}

This works because a protected member is accessible within its class and by derived class instances, so we are taking advantage of how the .Net framework behaves.

So now you can test IsAuthorized in the unit tests and trust the code in the future.

I only trust Batman ❤️