How to Unit Test Abstract Classes: Extend with Stubs

How to unit test abstract classes: extend with stubs?

There are two ways in which abstract base classes are used.

  1. You are specializing your abstract object, but all clients will use the derived class through its base interface.

  2. You are using an abstract base class to factor out duplication within objects in your design, and clients use the concrete implementations through their own interfaces.!


Solution For 1 - Strategy Pattern

Option1

If you have the first situation, then you actually have an interface defined by the virtual methods in the abstract class that your derived classes are implementing.

You should consider making this a real interface, changing your abstract class to be concrete, and take an instance of this interface in its constructor. Your derived classes then become implementations of this new interface.

IMotor

This means you can now test your previously abstract class using a mock instance of the new interface, and each new implementation through the now public interface. Everything is simple and testable.


Solution For 2

If you have the second situation, then your abstract class is working as a helper class.

AbstractHelper

Take a look at the functionality it contains. See if any of it can be pushed onto the objects that are being manipulated to minimize this duplication. If you still have anything left, look at making it a helper class that your concrete implementation take in their constructor and remove their base class.

Motor Helper

This again leads to concrete classes that are simple and easily testable.


As a Rule

Favor complex network of simple objects over a simple network of complex objects.

The key to extensible testable code is small building blocks and independent wiring.


Updated : How to handle mixtures of both?

It is possible to have a base class performing both of these roles... ie: it has a public interface, and has protected helper methods. If this is the case, then you can factor out the helper methods into one class (scenario2) and convert the inheritance tree into a strategy pattern.

If you find you have some methods your base class implements directly and other are virtual, then you can still convert the inheritance tree into a strategy pattern, but I would also take it as a good indicator that the responsibilities are not correctly aligned, and may need refactoring.


Update 2 : Abstract Classes as a stepping stone (2014/06/12)

I had a situation the other day where I used abstract, so I'd like to explore why.

We have a standard format for our configuration files. This particular tool has 3 configuration files all in that format. I wanted a strongly typed class for each setting file so, through dependency injection, a class could ask for the settings it cared about.

I implemented this by having an abstract base class that knows how to parse the settings files formats and derived classes that exposed those same methods, but encapsulated the location of the settings file.

I could have written a "SettingsFileParser" that the 3 classes wrapped, and then delegated through to the base class to expose the data access methods. I chose not to do this yet as it would lead to 3 derived classes with more delegation code in them than anything else.

However... as this code evolves and the consumers of each of these settings classes become clearer. Each settings users will ask for some settings and transform them in some way (as settings are text they may wrap them in objects of convert them to numbers etc.). As this happens I will start to extract this logic into data manipulation methods and push them back onto the strongly typed settings classes. This will lead to a higher level interface for each set of settings, that is eventually no longer aware it's dealing with 'settings'.

At this point the strongly typed settings classes will no longer need the "getter" methods that expose the underlying 'settings' implementation.

At that point I would no longer want their public interface to include the settings accessor methods; so I will change this class to encapsulate a settings parser class instead of derive from it.

The Abstract class is therefore: a way for me to avoid delegation code at the moment, and a marker in the code to remind me to change the design later. I may never get to it, so it may live a good while... only the code can tell.

I find this to be true with any rule... like "no static methods" or "no private methods". They indicate a smell in the code... and that's good. It keeps you looking for the abstraction that you have missed... and lets you carry on providing value to your customer in the mean time.

I imagine rules like this one defining a landscape, where maintainable code lives in the valleys. As you add new behaviour, it's like rain landing on your code. Initially you put it wherever it lands.. then you refactor to allow the forces of good design to push the behaviour around until it all ends up in the valleys.

Test abstract class which extends another class

Mockito can't mock abstract classes. But you can have a subclass for your test purpose which implement your class B and then spy on it.

@RunWith(MockitoJUnitRunner.class)
public class BTest {

@InjectMocks
@Spy
private FakeB b;

@Test
public void testSomething() {
when(b.convert(any())).thenReturn(something);
}

public static class FakeB extends B {
protected Object convert(Object someobject) {
return null;
}
}
}

With this approach you can easily mock your abstract methods and test non-abstract ones in your abstract classes. Of course the downside is that you have to crate a fake test classes that subtypes your abstract classes. But I think it shouldn't be a big issue.

Testing concrete methods in abstract classes using subclasses

There are two options which immediately come to mind here.

Firstly, you could write an abstract test class, which handles testing these methods, and then the test classes for your concrete implementations do the rest. For example:

public abstract class YourAbstractClassTest {

protected abstract YourAbstractClass getInstance();

@Test
public void testThing() {
final YourAbstractClass instance = this.getInstance();
instance.callMethod();

Assertions.assertTrue(instance.someProperties());
}
}

Alongside:

public class ConcreteSubclassTest extends YourAbstractClassTest {
private final ConcreteSubclass instance = new ConcreteSubclass();

@Override
protected YourAbstractClass getInstance() {
return this.instance;
}

@Test
public void moreTesting() {
this.instance.implementationSpecificMethod();
}
}

You could also create a dummy subclass in a test class for it:

public class AbstractClassTest {
private final AbstractClass instance = new AbstractClass() {
@Override
public void abstractMethod() {
throw new UnsupportedOperationException();
}
}

@Test
public void testThing() {
this.instance.concreteMethod();
// Just make sure this doesn't ever go near the
// methods you dummied up above...
}
}

Unit testing a class that inherits from an abstract class

Your current setup won't work for one simple reason - Uow property is non-overridable and Moq's job is done at this point. Cannot override, cannot mock.

Easiest solution is to simply make that property overridable. Change your base class definition to:

public abstract class BaseService
{
protected virtual IDrawingSystemUow Uow { get; set; }
}

Now you can use Moq's protected feature (this requires you to include using Moq.Protected namespace in your test class):

// at the top of the file
using Moq.Protected;

// ...

var drawingSystemStub = new Mock<IDrawingSystemUow>();
var testedClass = new Mock<UserService>();
testedClass
.Protected()
.Setup<IDrawingSystemUow>("Uow")
.Returns(drawingSystemStub.Object);

// setup drawingSystemStub as any other stub

// exercise test
var result = testedClass.Object.UserExists(...);

How to test abstract class in Java with JUnit?

If you have no concrete implementations of the class and the methods aren't static whats the point of testing them? If you have a concrete class then you'll be testing those methods as part of the concrete class's public API.

I know what you are thinking "I don't want to test these methods over and over thats the reason I created the abstract class", but my counter argument to that is that the point of unit tests is to allow developers to make changes, run the tests, and analyze the results. Part of those changes could include overriding your abstract class's methods, both protected and public, which could result in fundamental behavioral changes. Depending on the nature of those changes it could affect how your application runs in unexpected, possibly negative ways. If you have a good unit testing suite problems arising from these types changes should be apparent at development time.

Unit testing methods implemented in Abstract Class without specific implementation

The shortest answer is that you are approaching the problem from the wrong end. Start with something simple that works, then you'll be able to test it. Add abstractions as you develop the program, don't start from abstractions, because you won't know what you will really need before you do it.

Also if you have utility methods that don't actually depend on your Player implementation then those clearly shouldn't be part of Player class.

Testing Abstract Classes

Unit testing of abstract classes doesn't necessary mean testing the interface, as abstract classes can have concrete methods, and this concrete methods can be tested.

It is not so uncommon, when writing some library code, to have certain base class that you expect to extend in your application layer. And if you want to make sure that library code is tested, you need means to UT the concrete methods of abstract classes.

Personally, I use PHPUnit, and it has so called stubs and mock objects to help you testing this kind of things.

Straight from PHPUnit manual:

abstract class AbstractClass
{
public function concreteMethod()
{
return $this->abstractMethod();
}

public abstract function abstractMethod();
}

class AbstractClassTest extends PHPUnit_Framework_TestCase
{
public function testConcreteMethod()
{
$stub = $this->getMockForAbstractClass('AbstractClass');
$stub->expects($this->any())
->method('abstractMethod')
->will($this->returnValue(TRUE));

$this->assertTrue($stub->concreteMethod());
}
}

Mock object give you several things:

  • you are not required to have concrete implementation of abstract class, and can get away with stub instead
  • you may call concrete methods and assert that they perform correctly
  • if concrete method relies to unimplemented (abstract) method, you may stub the return value with will() PHPUnit method

How to correctly use abstract classes (problems with testing)

The PLC data and the connection type are now separated in a clean way. I often see designs like your original one. They try to implement exchangable functionality by inheriting from the "common case". After a while they get really messy.

To enable the Connections to update data in PlcData you should consider the observer pattern, which enables you to keep the connections decoupled. The connections would provide ways of registering "callbacks" that would be called on certain state changes. If the amount of data is small, it could be passed along in the call or the callback function would "turn around" and pull the data from the connection.

interface Connection {
void registerLevelChange(Runnable callback);
}

class ModBusConnection implements Connection {
private List<Runnable> levelChangeCallbacks = new ArrayList<Runnable>();

public void registerLevelChange(Runnable callback) {
levelChangeCallbacks.add(callback);
}

void processIncomingData() {
if (level.hasChanged()) {
for (var cb: levelChangeCallbacks) {
cb.run();
}
}
}
}

class PlcData {
private Connection connection;

void someMethod() {
...
connection.registerLevelChange(() -> handleLevelChange());
...
}

void handleLevelChange() {
...
}
}

Should you unit test constructors of abstract classes and, if so, how?

This works but it's a bit dodgy.The constructor exception doesn't happen until you try to accesss some property of the mock. It does confirm that something is throwing the exception you want though.

[TestClass]
public class UnitTest1
{
[TestMethod()]
public void WebApiServiceBase_NullHttpClient_ThrowsArgumentNull()
{

var controller = new Mock<WebApiServiceBase>(MockBehavior.Loose,
//Pass null in to the constructor
null
);

var exception = Assert.ThrowsException<TargetInvocationException>(() =>
{
var httpClient = controller.Object.HttpClient;
});

Assert.IsTrue(exception.InnerException is ArgumentNullException ane && ane.ParamName == "httpClient");
}
}

But, you shouldn't design your classes like this because it makes them hard to test. Better to inject all the reusable code instead of making a base class. A good Http client abstraction would mean that you don't need to create a base class. Here is a good abstraction:

public interface IClient
{
/// <summary>
/// Sends a strongly typed request to the server and waits for a strongly typed response
/// </summary>
/// <typeparam name="TResponseBody">The expected type of the response body</typeparam>
/// <param name="request">The request that will be translated to a http request</param>
/// <returns>The response as the strong type specified by TResponseBody /></returns>
/// <typeparam name="TRequestBody"></typeparam>
Task<Response<TResponseBody>> SendAsync<TResponseBody, TRequestBody>(IRequest<TRequestBody> request);

/// <summary>
/// Default headers to be sent with http requests
/// </summary>
IHeadersCollection DefaultRequestHeaders { get; }

/// <summary>
/// Base Uri for the client. Any resources specified on requests will be relative to this.
/// </summary>
AbsoluteUrl BaseUri { get; }
}

Reference



Related Topics



Leave a reply



Submit