Hot questions for Using Mockito in inheritance

Question:

I have written a testclass for a baseclass that uses a factory. I @Mocked the factory to return a Mock object. It looks sort of like this.

class BaseClass{
  SomeFactory factory;

  public BaseClass(SomeFactory factory){
    this.factory=factory;
  }


  public void parse(){
     factory.createSomething();
  }
}

Now my (working) testclass looks like this.

@RunWith(MockitoJUnitRunner.class)
public class BaseTest {
  @Mock
  SomeFactory factory;
  @Mock
  SomeCreation crateation;

  BaseClass subject;



  @Before 
  public void setUp(){
    when(factory.createSomething()).thenReturn(someCreation);
    subject = new BaseClass(factory);
  }

  @Test
  testParse(){
    subject.Parse();
    verify(factory).createSomething();
  }
 }

This all works fine, but now i have extended BaseClass (lets call it SubClass) and added some functionality. My SubClass also uses an extended factory (SubFactory). So i also want to extend BaseTest and run the same tests, because it does the exact same thing and something extra.

so i overrode the setUp() like so:

class SubTest extends BaseTest{

  @Mock
  SubFactory subFactory;
  @Mock
  Something something;

  @Override 
  public void setUp(){

    when(subFactory.createSomething()).thenReturn(
    factory = subFactory;
    subject = new SubClass(subFactory);
   } 
 }

This however doesn't work, because in the baseclass it throws an UnfinishedVerificationException saying:

Missing method call for verify(mock) here:

pointing to the verify in the BaseClass.

Any ideas on how to structure my test-cases that allows me to test the SubClass with the same tests as BaseClass?

Thank you,


Answer:

Do not extend test cases! Even though there will be (lots of) duplicated code, it's easier to be read and followed.

So, the subclass test should not extend the BaseClass test, but rather re-use the tests on the functionality, which will not be overwritten in the subclass. Also, a getter for the factory would be needed to better customize the behavior on the mocked factory:

class SubClass extends BaseClass {
    SubClass(SubFactory factory) {
        super(factory);
    }

    SubFactory getFactory() { return factory; }

    public void parse() {
       getFactory().createSomething();
    }
}

class SubTest {

  @Mock
  SubFactory subFactory;

  @Mock
  Something something;

  @Mock
  SubCreation someSubCreation;

  SubClass subject = new SubClass(subFactory);

  public void setUp() {
    when(subFactory.createSomething()).thenReturn(someSubCreation);
  }

}

Question:

I have two classes (B & C) that extend from A.

I am trying to write a unit test in a way that I can just pass in concrete implementations of B and C and let them run. For example:

abstract class A {
  abstract doSomething();

  public static void send(A a){
      // sends a off
  }
}

class B extends A {
  public void doSomething(){
    this.send(this)
  }

class C extends A {
  public void doSomething(){
    this.send(this);
    this.write(this)
  }
  public void write(A a){
     //writes A to file
  }
}

Now, I am looking for a way to unit test this abstractly and only have to pass in implementations and let the unit test run. For example:

//setup junit testsuite info
class TestClassA {

  private A theClass;

  public void testDoSomething(){
     this.theClass.doSomething();
  }
}

 // would like to be able to do
class Runner {
   B b = new B();
   C c = new C();

   // run TestClassA with b (I know this doesnt work, but this is what I'd like to do)
   TestClassA.theClass = b;
   TestClassA.run();


   // run TestClassA with c (I know this doesnt work, but this is what I'd like to do)
   TestClassA.theClass = c;
   TestClassA.run();
}

Does anyone have any ideas on how this can be accomplished?


Answer:

@RunWith(Parameterized.class)
public class ATest {
    private A theClass;

    public ATest(A theClass) {
        this.theClass= theClass;
    }

    @Test
    public final void doSomething() {
        // make assertions on theClass.doSomething(theClass)
    }


    @Parameterized.Parameters
    public static Collection<Object[]> instancesToTest() {
        return Arrays.asList(
                    new Object[]{new B()},
                    new Object[]{new C()}
        );
    }
}