tiebin-zhang / powermock

Automatically exported from code.google.com/p/powermock
Apache License 2.0
0 stars 0 forks source link

ExpectedException.expectMessage AssertionError lost with PowerMockRunner #376

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?

Run this test class:

@RunWith(PowerMockRunner.class)
public class ExpectedExceptionTest {

    @Rule
    public ExpectedException thrown = ExpectedException.none();

    @Test
    public void testExpectedException()  {
        thrown.expect(IllegalStateException.class);
        thrown.expectMessage("expected message");

        throw new IllegalStateException("surprise message");
    }

}

What is the expected output? What do you see instead?

Expected output:
java.lang.AssertionError: 
Expected: (exception with message a string containing "expected message" and an 
instance of java.lang.IllegalStateException)
     got: <java.lang.IllegalStateException: surprise message>

Instead I see:
java.lang.IllegalStateException: surprise message

Without the PowerMockRunner the expected AssertionError is shown in the output.

What version of the product are you using? On what operating system?
1.4.11

Original issue reported on code.google.com by dietrich...@gmail.com on 9 Mar 2012 at 6:58

GoogleCodeExporter commented 9 years ago
What version of Junit are you using?

Original comment by johan.ha...@gmail.com on 9 Mar 2012 at 7:36

GoogleCodeExporter commented 9 years ago
I also experienced this when using PowerMockRule and ExpectedException rule. 
It seems the problem is the order of the Rule's statements being executed and 
the classloading PowerMock does. The exception is thrown OK through to 
ExpectedExceptionStatement, but the ExpectedExceptionStatement itself is a 
different object than the one that is visible to the test (I suspect due to 
classloading).
That means that the "expect" methods in the Test are working with another 
Object than the one that does the "handleException", and so there are no 
matchers and the whole thing fails.

A workaround is as follows:
1.) create a class PowerMockTestRule which wraps PowerMockRule to make it 
implement TestRule:

import java.lang.reflect.Method;

import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.Statement;
import org.powermock.modules.junit4.rule.PowerMockRule;

public class PowerMockTestRule implements TestRule {

    private final PowerMockRule rule;
    public PowerMockTestRule(PowerMockRule rule) {
        this.rule = rule;
    }
    @Override
    public Statement apply(Statement base, Description description) {
        return rule.apply(base, createFrameworkMethod(description), getTestObject(description));
    }
    private FrameworkMethod createFrameworkMethod(Description description) {
        try {
            String methodName = description.getMethodName();
            Class c = getTestClass(description);
            Method m = c.getDeclaredMethod(methodName);
            return new FrameworkMethod(m);
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }
    private Class<?> getTestClass(Description description) {
        return description.getTestClass();
    }

    private Object getTestObject(Description description) {
        try {
            return getTestClass(description).newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new IllegalStateException(e);
        }
    }

}

2.) Use RuleChain to define the order of the Rules:
public ExpectedException thrown = ExpectedException.none();
@Rule public TestRule chain = RuleChain
            .outerRule(new PowerMockTestRule(new PowerMockRule()))
            .around(thrown);

I don't know if this is feasible for a general solution, but in my case, it 
works.

PS: Junit used: 4.11, Powermock used: 1.5.1

Original comment by ronald.b...@gmail.com on 26 Sep 2013 at 4:04

GoogleCodeExporter commented 9 years ago
Update: instead of the Powermock specific PowerMockTestRule above i am now 
using a more generic Version: TestRuleAdapter:

import java.lang.reflect.Method;

import org.junit.rules.MethodRule;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.Statement;

public class TestRuleAdapter implements TestRule {

    private final MethodRule rule;
    public TestRuleAdapter(MethodRule rule) {
        this.rule = rule;
    }
    @Override
    public Statement apply(Statement base, Description description) {
        return rule.apply(base, createFrameworkMethod(description), getTestObject(description));
    }
    private FrameworkMethod createFrameworkMethod(Description description) {
        try {
            String methodName = description.getMethodName();
            Class<?> c = getTestClass(description);
            Method m = c.getDeclaredMethod(methodName);
            return new FrameworkMethod(m);
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }
    private Class<?> getTestClass(Description description) {
        return description.getTestClass();
    }

    private Object getTestObject(Description description) {
        try {
            return getTestClass(description).newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new IllegalStateException(e);
        }
    }

}

Original comment by ronald.b...@gmail.com on 26 Sep 2013 at 8:02

GoogleCodeExporter commented 9 years ago
Thanks for sharing this. It wouldn't be possible for you to try to resolve this 
issue in the PowerMockRule?  I would be really glad if we could get this fixed 
to the next release.

Original comment by johan.ha...@gmail.com on 27 Sep 2013 at 5:16

GoogleCodeExporter commented 9 years ago
Is this expected to be fixed anytime soon? I am on JUnit 4.12, PowerMock 1.6.1, 
and Mockito 1.10.8 and this still doesn't work. Anytime I use PowerMock on a 
test class I have to revert to try/catch to validate exceptions.

Original comment by kyk...@gmail.com on 6 Feb 2015 at 7:23

GoogleCodeExporter commented 9 years ago
This is a serious problem. To fix it, all that needs to be done is for 
PowerMockRule to implement TestRule so that it can be chainable with RuleChain.

It is currently not possible to submit issues on Github for this that I could 
see.

Original comment by ryan.dan...@gmail.com on 24 Mar 2015 at 10:03

GoogleCodeExporter commented 9 years ago
No issues are currently reported here (but we will move to Github). Please 
submit a pull request at Github and I'll include it.

Original comment by johan.ha...@gmail.com on 26 Mar 2015 at 7:55