svjn
svjn

Reputation: 914

Junit test cases fail for abstract method

I have an abstract method checkStatus() which has implementations in Checker.java class. But when I execute the Junit test case on abstract class method validate() that in-turn calls checkStatus(), fails due to missing spring dependency in Checker.java class.

Details provided below.

Abstract class:

public abstract class MyAbstractClass
{
    protected abstract boolean checkStatus();

    public boolean validate()
    {
        //Some code
        return checkStatus();
    }
}

Implementation class:

public class Checker extends MyAbstractClass
{
    @Autowired
    private StatusHelper helper;

    public void setHelper(StatusHelper helper){
        this.helper = helper;
    }

    @Override
    public boolean checkStatus() throws Exception{
        if(null == helper){
            throw new Exception("Helper is null");
        }

        return helper.validateStatus();
    }
}

JUnit test:

class AbstractClassTest
{
    MyAbstractClass absClass = Mockito.mock(Checker.class, Mockito.CALLS_REAL_METHODS);

    @Test
    public void testStatusOfChecker()throws Exception {
        boolean status = absClass.validate();
        assertEquals(status, true);
    }
}

I believe I can inject the helper object manually like the following

Checker check = mock(Checker.class);
StatusHelper helper = mock(StatusHelper.class);
check.setHelper(helper);

but the problem here is, I cannot inject directly to absClass object as the setHelper() is not inherited.

I can instead write test case directly to subclass, but I needed this way to test some other functionality in validate() method of abstract class.

Can someone help me how to set helper object to the sub class or is there different way to do it in Junit? Any help or links that contain relevant info is highly appreciable. Thanks,

Upvotes: 0

Views: 858

Answers (1)

Stefan Birkner
Stefan Birkner

Reputation: 24510

The only way to test an abstract class is by testing an implementation (which could be an anonymous class).

public class AbstractClassTest {
  @Test
  public void testStatusOfChecker() throws Exception {
    MyAbstractClass object = new MyAbstractClass() {
      protected boolean checkStatus() {
        return true; //this is the place to provide the expected value
      }
    }
    boolean status = absClass.validate();
    assertEquals(status, true);
  }
}

If you want to test the Checker implementation then you must not mock it.

public class CheckerTest {
  @Test
  public void test() {
    StatusHelper helper = mock(StatusHelper.class);
    Checker checker = new Checker();
    checker.setHelper(helper);
    when(helper.validate()).thenReturn(true);
    boolean status = checker.validate();
    assertEquals(status, true);
  }
}

By the way I strongly recommend to use constructor injection (see Why field injection is evil). The test would then look like this

public class CheckerTest {
  @Test
  public void test() {
    StatusHelper helper = mock(StatusHelper.class);
    Checker checker = new Checker(helper);
    when(helper.validate()).thenReturn(true);
    boolean status = checker.validate();
    assertEquals(status, true);
  }
}

Upvotes: 2

Related Questions