18

Sometimes, you want to test a class method and you want to do an expectation on a call of a super class method. I did not found a way to do this expectation in java using easymock or jmock (and I think it is not possible).

There is a (relative) clean solution, to create a delegate with the super class method logic and then set expectations on it, but I don't know why and when use that solution ¿any ideas/examples?

Thanks

arielsan
  • 418
  • 2
  • 4
  • 11

6 Answers6

12

Well, you can if you want to. I don't know if you are familiar with JMockit, go check it out. The current version is 0.999.17 In the mean time, let's take a look at it...

Assume the following class hierarchy:

public class Bar {
    public void bar() {
        System.out.println("Bar#bar()");
    }
}

public class Foo extends Bar {
    public void bar() {
        super.bar();
        System.out.println("Foo#bar()");
    }
}

Then, using JMockit in your FooTest.java you can validate that you're actually making a call to Bar from Foo.

@MockClass(realClass = Bar.class)
public static class MockBar {
    private boolean barCalled = false;

    @Mock
    public void bar() {
        this.barCalled = true;
        System.out.println("mocked bar");
    }
}

@Test
public void barShouldCallSuperBar() {
    MockBar mockBar = new MockBar();
    Mockit.setUpMock(Bar.class, mockBar);

    Foo foo = new Foo();
    foo.bar();

    Assert.assertTrue(mockBar.barCalled);

    Mockit.tearDownMocks();
}
kan
  • 28,279
  • 7
  • 71
  • 101
Cem Catikkas
  • 7,171
  • 4
  • 29
  • 33
  • 1
    It's also possible to do it using the JMockit Expectations API (see the new project site at http://code.google.com/p/jmockit). – Rogério Jan 12 '10 at 01:23
8

Expanding on @Cem Catikkas answer, using JMockit 1.22:

@Test
public void barShouldCallSuperBar() {
    new MockUp<Bar>() {
        @Mock
        public void bar() {
            barCalled = true;
            System.out.println("mocked bar");
        }
    };

    Foo foo = new Foo();
    foo.bar();

    Assert.assertTrue(mockBar.barCalled);
}

No need for the static class annotated with @MockClass, it is replaced by the MockUp class.

5

I don't think I'd mock out a super call - it feels to me like the behaviour there is part of the behaviour of the class itself, rather than the behaviour of a dependency. Mocking always feels like it should be to do with dependencies more than anything else.

Do you have a good example of the kind of call you want to mock out? If you want to mock out a call like this, would it be worth considering composition instead of inheritance?

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 5
    Yes, but you want to test the subclass isolated, you know the super class works fine, you don't wan to test it again. – arielsan Mar 08 '09 at 15:31
  • Please, just don't do this. You're breaking encapsulation to lock the implementation into the test. Unless this code never changes again, you'll regret it. – Steve Freeman Mar 13 '11 at 15:35
1

There are several tests that do just that (ie specify an expected invocation on a super-class method) using the JMockit Expectations API, in the Animated Transitions sample test suite. For example, the FadeInTest test case.

Rogério
  • 16,171
  • 2
  • 50
  • 63
  • 2
    This test was meanwhile moved to: http://code.google.com/p/jmockit/source/browse/trunk/samples/AnimatedTransitions/test/org/jdesktop/animation/transitions/effects/FadeInTest.java – Konstantin Pribluda Nov 08 '11 at 09:09
  • Moved again: https://github.com/jmockit/jmockit1/blob/master/samples/AnimatedTransitions/test/org/jdesktop/animation/transitions/effects/FadeInTest.java – jordanpg Sep 25 '15 at 14:33
0

No, there is no way of mocking super class methods with jMock.

However there is a quick-and-dirty solution to your problem. Suppose you have class A and class B extends A. You want to mock method A.a() on B. You can introduce class C extends B in your test code and override the method C.a() (just call super, or return null, id does not matter). After that mock C and use the mock everywhere, where you'd use B.

Vivek
  • 1,640
  • 1
  • 17
  • 34
  • It is not so dirty. We can create the C class as inner in the test class. – Gangnus Jan 27 '16 at 11:46
  • 1
    This actually doesn't work if you are calling the super method by the same name. B.a() calls A.a(). If you introduce C.a() and call super, you just end up C.a() -> B.a() -> A.a() – david.tanner Mar 13 '18 at 21:30
-1

intercepting a super call is much too fine-grained. Don't overdo the isolation.

Steve Freeman
  • 2,707
  • 19
  • 14