junit-team / junit4

A programmer-oriented testing framework for Java.
https://junit.org/junit4
Eclipse Public License 1.0
8.53k stars 3.28k forks source link

Assume.assumeTrue not working as excepted when called in @Before and @After #1232

Closed ghilainm closed 8 years ago

ghilainm commented 8 years ago

See below the test class, with a dummy test doing nothing.

package my.package;

import org.junit.After;
import org.junit.Assume;
import org.junit.Before;

public class Test {

    @Before
    public void init(){
        Assume.assumeTrue(false);
    }

    @After
    public void cleanUp(){
        Assume.assumeTrue(false);
    }

    @org.junit.Test
    public void dummyTest(){

    }
}

If I don't call the Assume.assumeTrue in the @After everything is fine. But calling the assumeTrue method in @Before and @After the JUnit test fails with the following error.

 org.junit.AssumptionViolatedException: got: <false>, expected: is <true>
    at org.junit.Assume.assumeThat(Assume.java:95)
    at org.junit.Assume.assumeTrue(Assume.java:41)
    at my.package.Test.init(Test.java:11)
    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:497)
    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.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
    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:497)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
smadasu commented 8 years ago

Hi ghilainm, I think When you don't call the Assume.assumeTrue in the @After everything is not fine. The test is skipped. It is not successfully run. Could you please check this again?

If you do the following you will get a stack trace and the test is skipped.

... @Before public void init() { try { Assume.assumeTrue(false); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); throw e; } } ...

jmcshane commented 8 years ago

+1 on this. I did a little more investigating on this and it appears that the test fails whenever assumptions fail in both the @Before and @After blocks. I added some lines to the dummy test method as well with the same result. Here's a further example of a test that should be skipped, but fails:

import org.junit.After;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;

import org.hamcrest.CoreMatchers;

public class ExampleTest {

    @Before
    public void init(){
        Assume.assumeTrue(false);
    }

    //This test fails?
    @Test
    public void dummyTest(){
        Assert.assertEquals(1, 1);
    }

    @After
    public void cleanUp(){
        Assume.assumeThat(1, CoreMatchers.equalTo(2));
    }
}
marcphilipp commented 8 years ago

Assumptions were never intended to be used in @After methods. They were originally introduced for the Theories runner to enable specification of preconditions for a @Theory. The can be used in regular @Test methods as well as in @Before and @BeforeClass. In the latter case, a special event is sent to RunListener implementations, namely testAssumptionFailure. Most IDEs and build tools will report this as "skipped" (like testIgnored).

IMHO it does not make sense to use assumptions after the test has already been executed, i.e. in methods annotated with @After or @AfterClass. Maybe you can shed more light on what you are trying to accomplish?

ghilainm commented 8 years ago

It makes sense if you want to skip some clean-up which must be done after the test but cannot be done for some conditions.

marcphilipp commented 8 years ago

I'm afraid you'll have to use an if in this case.

ghilainm commented 8 years ago

^^, wouldn't it be possible to extends the support to the @After? Because it seems a convenient way of skipping code (and seems logical as it works for @Before)!

stefanbirkner commented 8 years ago

The assume feature is not meant to be used for skipping code. The intention of assume is to dynamically ignore tests.

ghilainm commented 8 years ago

Fine for me but then the test should be skipped as soon as I did the Assume.assumeTrue in the @Before which is even better for me!

stefanbirkner commented 8 years ago

It is skipped. The test test() of the following example is skipped:

public class ExampleTest {
  @Before
  public void skipTest() {
    assumeTrue(false);
    fail();
  }

  @Test
  public void test() {
    fail();
  }
}