Can I mock a super class method call?
Asked Answered
S

6

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

Solarize answered 7/3, 2009 at 23:54 Comment(1)
I can't think of a really compelling reason why this is a bad idea. +1 for brilliant question.Soothfast
L
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();
}
Lambrecht answered 8/3, 2009 at 4:49 Comment(1)
It's also possible to do it using the JMockit Expectations API (see the new project site at code.google.com/p/jmockit).Alejandro
F
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.

Further answered 28/3, 2016 at 15:57 Comment(0)
K
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?

Koontz answered 8/3, 2009 at 0:23 Comment(2)
Yes, but you want to test the subclass isolated, you know the super class works fine, you don't wan to test it again.Solarize
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.Freaky
T
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.

Tendentious answered 21/6, 2009 at 22:39 Comment(2)
This test was meanwhile moved to: code.google.com/p/jmockit/source/browse/trunk/samples/…Quarterstaff
Moved again: github.com/jmockit/jmockit1/blob/master/samples/…Carpentaria
G
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.

Glister answered 5/3, 2012 at 16:39 Comment(2)
It is not so dirty. We can create the C class as inner in the test class.Jemena
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()Rothko
F
-1

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

Freaky answered 21/5, 2009 at 12:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.