【问题标题】:JUnit ExpectedException rule doesn't workJUnit ExpectedException 规则不起作用
【发布时间】:2015-06-11 16:04:32
【问题描述】:

我有一个我应该测试的方法:

public void createNode(String name, String primaryNodeType, String[] mixinNodeTypes) throws RepositoryException {
    final Node parentNode = this.parentNodeStack.peek();
    boolean isParentImport = (name == null && isParentNodeImport);
    if (name == null) {
        if (this.parentNodeStack.size() > 1) {
            throw new RepositoryException("Node needs to have a name.");
        }
        name = this.defaultName;
    }
    //other stuff
}

在我的测试中,我输入了方法参数,哪个方法应该抛出 RepositoryException(第 6 行)。

@RunWith(JMock.class)
public class DefaultContentCreatorTest {

    static final String DEFAULT_NAME = "default-name";
    final Mockery mockery = new JUnit4Mockery();
    DefaultContentCreator contentCreator;

    Session session;
    Node parentNode;
    Property prop;

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

    @Before
    public void setup() throws Exception {
        final SlingRepository repo = RepositoryProvider.instance().getRepository();
        session = repo.loginAdministrative(null);
        contentCreator = new DefaultContentCreator(null);
        contentCreator.init(U.createImportOptions(true, true, true, false, false),
                new HashMap<String, ContentReader>(), null, null);
        parentNode = session.getRootNode().addNode(getClass().getSimpleName()).addNode(uniqueId());
    }

    @After
    public void cleanup() throws RepositoryException {
        if(session != null) {
            session.save();
            session.logout();
            session = null;
        }
    }

    @Test
    public void createNodeWithoutNameAndTwoInStack() throws RepositoryException {
        contentCreator.init(U.createImportOptions(true, true, true, false, false),
                new HashMap<String, ContentReader>(), null, null);
        //Making parentNodeStack.size() == 1
        contentCreator.prepareParsing(parentNode, DEFAULT_NAME);
        //Making parentNodeStack.size() == 2
        contentCreator.createNode(uniqueId(), null, null);

        //contentCreator.createNode method should now throw an exception
        thrown.expect(RepositoryException.class); //Doesn't work
        thrown.expectMessage("Node needs to have a name."); //Doesn't work
        contentCreator.createNode(null, null, null);
    }
}

但是,测试失败,正是这个 RepositoryException。我做错了什么?顺便说一句,如果我使用 @Test(expected = RepositoryException.class) 一切正常。

UPD:我正在为 Apache Sling 类之一编写单元测试。你可以看看这个班here UPD2:有一个失败的测试异常堆栈跟踪:

javax.jcr.RepositoryException: Node needs to have a name.
at org.apache.sling.jcr.contentloader.internal.DefaultContentCreator.createNode(DefaultContentCreator.java:225)
at org.apache.sling.jcr.contentloader.internal.DefaultContentCreatorTest.createNodeWithoutNameAndTwoInStack(DefaultContentCreatorTest.java:278)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68)
at org.jmock.integration.junit4.JMock$1.invoke(JMock.java:37)
at org.junit.internal.runners.MethodRoadie.runTestMethod(MethodRoadie.java:107)
at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:88)
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:96)
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:86)
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49)
at org.junit.internal.runners.JUnit4ClassRunner.invokeTestMethod(JUnit4ClassRunner.java:100)
at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:61)
at org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:54)
at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:33)
at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:45)
at org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:52)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)

如您所见,它在第 278 行抛出异常,这是 contentCreator.createNode(null, null, null); 方法调用的行。

【问题讨论】:

  • 你能给出一个完整且可重现的例子吗?
  • 只调试这个 org.junit.rules.ExpectedException.ExpectedExceptionStatement#evaluate
  • @SotiriosDelimanolis 完成。
  • 测试失败,因为上面设置预期异常详细信息的代码正在引发异常。向我们展示完整的堆栈跟踪。
  • 嗯...也许JMock 跑步者搞砸了...请尝试删除`@RunWith(JMock.class)

标签: java junit


【解决方案1】:

总结一下来自 cmets 的讨论:解决方案是删除JMock jUnit runner。

【讨论】:

  • 您必须使用旧版本的 JMock。较新的版本扩展了BlockJUnit4ClassRunner(不是org.junit.internal.runners.JUnit4ClassRunner),因此支持规则
【解决方案2】:

尝试将你的 throw.expect 放在你期望异常的实际调用之前

@Test
public void createNodeWithoutNameAndTwoInStack() throws RepositoryException {
    thrown.expect(RepositoryException.class); //Doesn't work
    thrown.expectMessage("Node needs to have a name."); //Doesn't work 

    contentCreator.init(U.createImportOptions(true, true, true, false, false),
            new HashMap<String, ContentReader>(), null, null);

    //Making parentNodeStack.size() == 1
    contentCreator.prepareParsing(parentNode, DEFAULT_NAME);

    //Making parentNodeStack.size() == 2
    contentCreator.createNode(uniqueId(), null, null);

    // method should now throw an exception
    contentCreator.createNode(null, null, null);
}

【讨论】:

  • 这是一个错误的想法,因为现在你不知道哪一行应该抛出异常。如果有老式的try-catch会更好......
  • 感谢您的回答。但是它对我没有帮助。我的方法仍然因此异常而失败。顺便说一句,我还认为我应该在此异常将引发的方法之前调用 ExpectedException#expect() 一行。
  • @Ajan...但是测试的最后一行不总是您期望的异常吗?如果您期望来自特定方法调用的异常,我看不出有任何理由继续测试。这可能只是一个偏好问题,但我认为使用 ExpectedException 类比使用 try-catch 更干净。在我看来,在顶部声明它可以清楚地表明测试的预期。
  • @malificent :它清楚地表明了预期,但是......您正在丢失有关预期位置的信息。
  • @Ajan:除了测试的最后一行之外,还会在哪里出现异常?如果您预计某个特定点会出现异常,则没有理由继续测试,对吗?
猜你喜欢
  • 2020-09-03
  • 1970-01-01
  • 2015-07-08
  • 2020-10-20
  • 2014-05-24
  • 1970-01-01
  • 2022-01-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多