java - with - unit test abstract class python




How to unit test abstract classes: extend with stubs? (10)

I was wondering how to unit test abstract classes, and classes that extend abstract classes.

Should I test the abstract class by extending it, stubbing out the abstract methods, and then test all the concrete methods? Then only test the methods I override, and test the abstract methods in the unit tests for objects that extend my abstract class?

Should I have an abstract test case that can be used to test the methods of the abstract class, and extend this class in my test case for objects that extend the abstract class?

Note that my abstract class has some concrete methods.


First if abstract class contained some concrete method i think you should do this considered this example

 public abstract class A 

 {

    public boolean method 1
    {
        // concrete method which we have to test.

    }


 }


 class B extends class A

 {

      @override
      public boolean method 1
      {
        // override same method as above.

      }


 } 


  class Test_A 

  {

    private static B b;  // reference object of the class B

    @Before
    public void init()

      {

      b = new B ();    

      }

     @Test
     public void Test_method 1

       {

       b.method 1; // use some assertion statements.

       }

   }

Following @patrick-desjardins answer, I implemented abstract and it's implementation class along with @Test as follows:

Abstarct class - ABC.java

import java.util.ArrayList;
import java.util.List;

public abstract class ABC {

    abstract String sayHello();

    public List<String> getList() {
        final List<String> defaultList = new ArrayList<>();
        defaultList.add("abstract class");
        return defaultList;
    }
}

As Abstract classes cannot be instantiated, but they can be subclassed, concrete class DEF.java, is as follows:

public class DEF extends ABC {

    @Override
    public String sayHello() {
        return "Hello!";
    }
}

@Test class to test both abstract as well as non-abstract method:

import org.junit.Before;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.contains;
import java.util.Collection;
import java.util.List;
import static org.hamcrest.Matchers.equalTo;

import org.junit.Test;

public class DEFTest {

    private DEF def;

    @Before
    public void setup() {
        def = new DEF();
    }

    @Test
    public void add(){
        String result = def.sayHello();
        assertThat(result, is(equalTo("Hello!")));
    }

    @Test
    public void getList(){
        List<String> result = def.getList();
        assertThat((Collection<String>) result, is(not(empty())));
        assertThat(result, contains("abstract class"));
    }
}

I would argue against "abstract" tests. I think a test is a concrete idea and doesn't have an abstraction. If you have common elements, put them in helper methods or classes for everyone to use.

As for testing an abstract test class, make sure you ask yourself what it is you're testing. There are several approaches, and you should find out what works in your scenario. Are you trying to test out a new method in your subclass? Then have your tests only interact with that method. Are you testing the methods in your base class? Then probably have a separate fixture only for that class, and test each method individually with as many tests as necessary.


If an abstract class is appropriate for your implementation, test (as suggested above) a derived concrete class. Your assumptions are correct.

To avoid future confusion, be aware that this concrete test class is not a mock, but a fake.

In strict terms, a mock is defined by the following characteristics:

  • A mock is used in place of each and every dependency of the subject class being tested.
  • A mock is a pseudo-implementation of an interface (you may recall that as a general rule, dependencies should be declared as interfaces; testability is one primary reason for this)
  • Behaviors of the mock's interface members -- whether methods or properties -- are supplied at test-time (again, by use of a mocking framework). This way, you avoid coupling of the implementation being tested with the implementation of its dependencies (which should all have their own discrete tests).

If your abstract class contains concrete functionality that has business value, then I will usually test it directly by creating a test double that stubs out the abstract data, or by using a mocking framework to do this for me. Which one I choose depends a lot on whether I need to write test-specific implementations of the abstract methods or not.

The most common scenario in which I need to do this is when I'm using the Template Method pattern, such as when I'm building some sort of extensible framework that will be used by a 3rd party. In this case, the abstract class is what defines the algorithm that I want to test, so it makes more sense to test the abstract base than a specific implementation.

However, I think it's important that these tests should focus on the concrete implementations of real business logic only; you shouldn't unit test implementation details of the abstract class because you'll end up with brittle tests.


One of the main motivations for using an abstract class is to enable polymorphism within your application -- i.e: you can substitute a different version at runtime. In fact, this is very much the same thing as using an interface except the abstract class provides some common plumbing, often referred to as a Template pattern.

From a unit testing perspective, there are two things to consider:

  1. Interaction of your abstract class with it related classes. Using a mock testing framework is ideal for this scenario as it shows that your abstract class plays well with others.

  2. Functionality of derived classes. If you have custom logic that you've written for your derived classes, you should test those classes in isolation.

edit: RhinoMocks is an awesome mock testing framework that can generate mock objects at runtime by dynamically deriving from your class. This approach can save you countless hours of hand-coding derived classes.


This is the pattern I usually follow when setting up a harness for testing an abstract class:

public abstract class MyBase{
  /*...*/
  public abstract void VoidMethod(object param1);
  public abstract object MethodWithReturn(object param1);
  /*,,,*/
}

And the version I use under test:

public class MyBaseHarness : MyBase{
  /*...*/
  public Action<object> VoidMethodFunction;
  public override void VoidMethod(object param1){
    VoidMethodFunction(param1);
  }
  public Func<object, object> MethodWithReturnFunction;
  public override object MethodWithReturn(object param1){
    return MethodWihtReturnFunction(param1);
  }
  /*,,,*/
}

If the abstract methods are called when I don't expect it, the tests fail. When arranging the tests, I can easily stub out the abstract methods with lambdas that perform asserts, throw exceptions, return different values, etc.


To make an unit test specifically on the abstract class, you should derive it for testing purpose, test base.method() results and intended behaviour when inheriting.

You test a method by calling it so test an abstract class by implementing it...


Write a Mock object and use them just for testing. They usually are very very very minimal (inherit from the abstract class) and not more.Then, in your Unit Test you can call the abstract method you want to test.

You should test abstract class that contain some logic like all other classes you have.






abstract-class