0

In the code base I have the following structure:

abstract class Bar{

    public Bar(){
        ....
    }

    ....        

    public Bar(int x, int y){

    }

    ....
}

Bar is then extended by Foo.

abstract class Foo extends Bar{

    public Foo(){
      super();

        ....
    }

    public Foo(int x){
      super(x,0);  // call parent's specific constructor
      ....
    }

    ....
}

I have tried the following jUnit test case, which cannot compile:

class FooTest{

    Foo _foo;

    @Test
    void testFooConstructor(){
        new Expectations(){
            Bar bar;
            {
                bar = new Bar(anyInt,0); // error, obviously Bar cannot be instantiated.
            }
        }

        _foo = new Foo(anyInt){ // empty implementation
            //Override any abstract methods
        }
    }

}

I have written the above approach because I saw this SO question, but the abstract class may not be initiated, and hence it fails.

Additionally, I have also tried:

class FooTest{

    Foo _foo;

    @Test
    void testFooConstructor(){

        _foo = new Foo(anyInt){ // empty implementation
            //Override any abstract methods
        }

        new Expectations(){
            Bar bar;
            {
                invoke(bar,"Bar",anyInt,0); //Invocations.invoke
            }
        }

        invoke(_foo,"Foo",anyInt);
    }

}

However, my test result is:

java.lang.IllegalArgumentException: No compatible method found: Bar(int,int) at unit.src.com.test.FooTest$1.(line number)

How can I achieve the desired result? Is there a way to implement this test?

Community
  • 1
  • 1
arin
  • 1,774
  • 22
  • 35
  • In your example code above `Foo` does not extend `Bar`. You might want to fix that up. – Perception Jan 18 '13 at 20:07
  • It's not clear what the "desired result" is here, i.e. what are you trying to achieve? – Oliver Charlesworth Jan 18 '13 at 20:07
  • @OliCharlesworth I would like to make sure that when I construct a new instance of Foo, the constructor of Bar is called correctly. – arin Jan 18 '13 at 20:10
  • 1
    @arin: But a superclass constructor will *always* be called, even if you don't specify `super()`... – Oliver Charlesworth Jan 18 '13 at 20:11
  • @OliCharlesworth right, I am considering that there might be multiple constructors and that the default one might have some behavior when some parameters are not passed when initiating. – arin Jan 18 '13 at 20:15
  • 1
    @arin: Are you saying that you want a test that proves that a *specific* base-class constructor was called? – Oliver Charlesworth Jan 18 '13 at 20:16
  • @OliCharlesworth yes, I need to clarify this point in the question. This situation, and that the parent is not concrete gives me the problem in the question. – arin Jan 18 '13 at 20:18
  • @arin: Ok, I understand now. I don't know what the solution is, but consider that as this isn't part of your class's public interface, it's perhaps not what unit-testing is aimed at. – Oliver Charlesworth Jan 18 '13 at 20:20
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/22995/discussion-between-arin-and-oli-charlesworth) – arin Jan 18 '13 at 20:30
  • 1
    The `invoke(bar, ...)` call in the second version of the test could never work because `invoke` is only for *methods*. For constructors, the `newInstance(...)` methods should be used instead. However, I don't think it would work in the case of an `abstract` constructor. – Rogério Jan 21 '13 at 13:13

2 Answers2

2

A subclass must always call a super constructor, either implicit (that also means, calling

super()

in your constructor is redundant) or explicit (with parameters). If you want to test this, test the observable behaviour, i.e. what the invocation of the super constructor would do that you can test.

koljaTM
  • 10,064
  • 2
  • 40
  • 42
  • Thank you, I know that is a way to test it, yet just checking that the appropriate constructor is called is much easier; the hierarchy is very bloated and checking the constructor call would be much less time consuming than checking specific behavior. – arin Jan 18 '13 at 20:32
1

This is an unusual testing scenario, but it can be done using JMockit with a @Mock method for the constructor in the abstract base class:

public class FooTest
{
    @Test
    void verifyCallToSuperConstructor()
    {
        new MockUp<Bar>() {
            @Mock(invocations = 1) // verifies one call will occur
            void $init(int x, int y)
            {
                assertEquals(0, y);
            }
        };

        new Foo(123);
    }
}
Rogério
  • 16,171
  • 2
  • 50
  • 63
  • could you explain how the `MockUp` and the `$init` are working? Couldn't find them in the tutorials. – arin Jan 26 '13 at 03:31
  • 1
    Instantiating a `MockUp` subclass automatically applies the `@Mock` methods it contains to the mocked type `T`. `$init` is the special mock method name for constructors of a mocked class `T`. More details in the [tutorial](http://jmockit.googlecode.com/svn/trunk/www/tutorial/StateBasedTesting.html#inline). – Rogério Jan 28 '13 at 14:10