jmockit / jmockit1

Advanced Java library for integration testing, mocking, faking, and code coverage
Other
465 stars 240 forks source link

automatic call to tearDown() broken #320

Closed PatrickSauts closed 8 years ago

PatrickSauts commented 8 years ago

Please provide the following information:

In 3 tests classes in @before I instantiate a mock class in charge of mocking a singleton made by a static factory We reuse the same thread in (maven)surefire for performance optimization

When running the tests (mvn tests) With Jmockit 1.26 I get java.lang.IllegalStateException: Duplicate application of the same mock-up class

It works fine with Jmockit 1.25

rliesenfeld commented 8 years ago

How would I reproduce the problem?

PatrickSauts commented 8 years ago

Running this in eclipse fails with 1.26 but passes with 1.25

@RunWith(JUnit4)
class JmockitTearDownTest {

  @Before
  void before(){
    //Mocking calling vertx services
    new ExternalGatewayServiceMock()

  }

  @After
  void after() {

  }

  @Test
  void test1() {
    Assert.assertTrue('Awesome Test',true)
  }

  @Test
  void test2() {
    Assert.assertTrue('Awesome Test',true)
  }

}
public class ExternalGatewayServiceMock extends MockUp<ExternalGatewayService> {
  private static final Logger LOG = LoggerFactory.getLogger(ExternalGatewayServiceMock.class);

  @Mock
  String callService(String uri, String method, Map<String, String> headers, Map<String, String> param, String entity){
    LOG.info("Mocking calling service: {}",uri);
    return StringUtils.EMPTY;
  }

}

This is groovy code but that shouldn't matter

The stackTrace

java.lang.IllegalStateException: Duplicate application of the same mock-up class
    at mockit.MockUp.findPreviouslyMockedClassIfMockUpAlreadyApplied(MockUp.java:165)
    at mockit.MockUp.<init>(MockUp.java:119)
    at com.rbcplatform.actors.mock.ExternalGatewayServiceMock.<init>(ExternalGatewayServiceMock.java:14)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.codehaus.groovy.reflection.CachedConstructor.invoke(CachedConstructor.java:83)
    at org.codehaus.groovy.runtime.callsite.ConstructorSite$ConstructorSiteNoUnwrapNoCoerce.callConstructor(ConstructorSite.java:105)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:239)
    at com.rbcplatform.actors.JmockitTearDownTest.before(JmockitTest.groovy:23)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
rliesenfeld commented 8 years ago

No, it definitely looks like the problem occurs because it's a Groovy test. Look at the following part of the stack trace:

    at com.rbcplatform.actors.mock.ExternalGatewayServiceMock.<init>(ExternalGatewayServiceMock.java:14)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.codehaus.groovy.reflection.CachedConstructor.invoke(CachedConstructor.java:83)
    at org.codehaus.groovy.runtime.callsite.ConstructorSite$ConstructorSiteNoUnwrapNoCoerce.callConstructor(ConstructorSite.java:105)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:239)
    at com.rbcplatform.actors.JmockitTearDownTest.before(JmockitTest.groovy:23)

It shows there is generated Groovy code between the call to the mockup constructor in the before method, and the entry into the mockup class constructor.

If you run the following Java version of the test class (which works fine) through the debugger, you'll see there is no intermediate code between those two points:

import org.junit.*;
import static org.junit.Assert.*;

public class JMockitTearDownTest {
    @Before
    public void before() {
        new ExternalGatewayServiceMock();
    }

    @Test
    public void test1() {
        String s = new ExternalGatewayService().callService("", "", null, null, "");
        assertEquals("", s);
    }

    @Test
    public void test2() {
        String s = new ExternalGatewayService().callService("", "", null, null, "");
        assertEquals("", s);
    }
}
PatrickSauts commented 8 years ago

I was already upset when @MockClass was removed and now you telling me I can't use JMockit anymore with Groovy. I don't know where you guys are going with this but it will be without me.

Bye bye. I'm gonna use PowerMockito and Mockito.

rliesenfeld commented 8 years ago

Groovy was never supported... if some Groovy-based test happened to work, it was merely by accident.

ibauersachs commented 8 years ago

@rliesenfeld I'm getting the Duplicate application exception with pure Java too. Two test classes, both defining an @BeforeClass where new new A(); is called (class A extends MockUp<Other>). Any chance that something goes wrong during the teardown (junit 4.12)?

Edit: We're using VertxUnitRunner. Explicitly calling the deprecated MockUp.tearDown() resolves the duplicate warning.