检查 Junit 中的 2 个期望值

发布于 2024-10-11 14:14:20 字数 1307 浏览 2 评论 0原文


我有一个 java 程序,它针对 2 个不同的场景抛出带有 2 条不同消息的异常,并且我希望 Junit 测试用例检查这两条消息是否相等。举个例子 -

public void amethod() {
           // do some processing
        if(scenario1 == true) {
            throw new MySystemException("An error occured due to case 1 being incorrect.");
        }
        else if(scenario2 == true) {
            throw new MySystemException("An error occured as case 2 could not be found");
        }
    }  

现在这个 JUnit 会是这样的 -

public void testAMethod() {
    // do something
    assertEquals("Expected", "Actual");
}

据我所知,在上面的例子中,如果我使用 Scenario1 异常消息,当抛出 异常时,junit 将失败场景2,反之亦然。
我想知道 Junit 中是否提供了任何其他方式可以使用这个测试方法并检查两条消息以使测试通过?
类似 OR 的东西,如果可能的话,提供带有这些预期消息的“预期”值。
我希望我的查询足够清楚。

谢谢

更新

很抱歉回复延迟,因为有其他紧急事务。
谢谢大家提出的非常好的建议,它确实帮助我现在更好地理解了。
最终,为了保持简单,我决定实施 Don Roby 建议的有点类似的解决方案。因此创建了一个新的测试类,如下所示 -

public void testAMethodScenario1() {
    // do the necessary
    assertEquals("Expected Exception Message 1", "Actual");
}

public void testAMethodScenario2() {
    // do the necessary
    assertEquals("Expected Exception Message 2", "Actual");
}  

再次感谢大家的回复。

I have a java program which throws an exception with 2 different messages for 2 different scenarios and I want the Junit test case to check for equality for both of these messages. As an example -

public void amethod() {
           // do some processing
        if(scenario1 == true) {
            throw new MySystemException("An error occured due to case 1 being incorrect.");
        }
        else if(scenario2 == true) {
            throw new MySystemException("An error occured as case 2 could not be found");
        }
    }  

Now the JUnit for this would be something like-

public void testAMethod() {
    // do something
    assertEquals("Expected", "Actual");
}

As I understand, in this above example, if I use the Scenario1 exception message the junit will fail when an exception is thrown for Scenario2 and vice versa.
I would like to know if there is any other way provided in Junit by which I can use this one test method and check for both the messages for the test to pass?
Something like an OR, if possible to provide the "Expected" value with both these expected message.
I hope my query is clear enough.

Thanks

UPDATE

Sorry for the delayed response, had got caught up with some other urgent matter.
Thank you all for the very nice suggestions, it certainly has helped me to understand a bit better now.
Eventually, to keep it rather simple I decided to implement a somewhat similar solution suggested by Don Roby. So created a new test class which looks like -

public void testAMethodScenario1() {
    // do the necessary
    assertEquals("Expected Exception Message 1", "Actual");
}

public void testAMethodScenario2() {
    // do the necessary
    assertEquals("Expected Exception Message 2", "Actual");
}  

Thank you all again for your responses.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

怀里藏娇 2024-10-18 14:14:20

我认为您需要手动捕获异常(对于每个场景)并单独检查消息:

try {
    // trigger scenario 1
    fail("An exception should have been thrown here !");
} catch (MySystemException e1) {
    assertEquals("Wrong error message", m1, e1.getMessage());
}

try {
    // trigger scenario 2
    fail("An exception should have been thrown here !");
} catch (MySystemException e2) {
    assertEquals("Wrong error message", m2, e2.getMessage());
}

当然,您可以将这些场景定义为枚举常量,然后简单地迭代它们并在循环中检查每个场景,因为“复制/粘贴设计模式”在上面的代码中非常明显。 :)

I think you need to manually catch the exception (for each scenario) and individually check the message:

try {
    // trigger scenario 1
    fail("An exception should have been thrown here !");
} catch (MySystemException e1) {
    assertEquals("Wrong error message", m1, e1.getMessage());
}

try {
    // trigger scenario 2
    fail("An exception should have been thrown here !");
} catch (MySystemException e2) {
    assertEquals("Wrong error message", m2, e2.getMessage());
}

Of course, you can have these scenarios defined as enum constants and simply iterate through them and check each of them within a loop, since the "copy/paste design pattern" is pretty obvious in the above code. :)

风筝在阴天搁浅。 2024-10-18 14:14:20

您似乎在这里问两件事,如何测试异常以及如何断言一个值与两个可能的期​​望值中的一个匹配。

要测试异常,您可以使用 JUnit4 注释:

@Test(expected=MySystemException.class)
public void testException() {
   amethod();
}

或在测试中使用 try-catch:

@Test
public void testException() {
   try {
      amethod();
      fail("MySystemException expected");
   }
   catch (MySystemException e) {
      // Success!
   }
}

如果您只有一条消息,在 try-catch 版本中,您可以使用 断言已获取该消息catch 块中的 AssertEquals

最好的测试将对您的两个场景进行单独的测试,并期望得到正确的单个消息。事实上,更好的代码对于这两种情况可能有不同的例外。

但无论如何,确实需要比简单相等更复杂的断言,并且 中有一个优雅的解决方案。 Hamcrest 匹配器。

在这种情况下使用它,您可以编写类似的内容(未经测试 - 不要完全相信我的语法):

@Test
public void testException() {
   try {
      amethod();
      fail("MySystemException expected");
   }
   catch (MySystemException e) {
      String expectedMessage1 = "An error occured due to case 1 being incorrect.";
      String expectedMessage2 = "An error occured as case 2 could not be found";
      assertThat(e.getMessage(), 
                 anyOf(equalTo(expectedMessage1), equalTo(expectedMessage2)));
   }
}

You seem to be asking two things here, how to test an exception and how to assert that a value matches either of two possible expected values.

To test for an exception, you can either use a JUnit4 annotation:

@Test(expected=MySystemException.class)
public void testException() {
   amethod();
}

or use a try-catch in your test:

@Test
public void testException() {
   try {
      amethod();
      fail("MySystemException expected");
   }
   catch (MySystemException e) {
      // Success!
   }
}

And if you have only one message, in the try-catch version you can assert that you got it with an AssertEquals in the catch block.

The best testing would have separate tests for your two scenarios, and expect the correct single message. Better code might in fact have distinct exceptions for the two situations.

But the need for a more complex assertion than simple equality does come up anyway, and there's an elegant solution for it in Hamcrest matchers.

Using that for this situation, you could write something like (untested - don't trust my syntax completely):

@Test
public void testException() {
   try {
      amethod();
      fail("MySystemException expected");
   }
   catch (MySystemException e) {
      String expectedMessage1 = "An error occured due to case 1 being incorrect.";
      String expectedMessage2 = "An error occured as case 2 could not be found";
      assertThat(e.getMessage(), 
                 anyOf(equalTo(expectedMessage1), equalTo(expectedMessage2)));
   }
}
梦回旧景 2024-10-18 14:14:20

你能预测会发生哪种情况吗?如果是这样,科斯蒂的答案就是正确的。如果没有,因为存在一些随机性或其他什么原因,你可以写:

@Test
public void testAmethodThrowsException() {
    try {
        amethod();
        fail("amethod() should have thrown an exception");
    }
    catch (MySystemException e) {
        String msg = e.getMessage();
        assertTrue("bad message: " + msg, msg.equals("An error occured due to case 1 being incorrect.") || msg.equals("An error occured as case 2 could not be found"));
    }
}

Can you predict which scenario will occur? If so, Costi's answer is correct. If not, because there's some randomness or whatever, you can write:

@Test
public void testAmethodThrowsException() {
    try {
        amethod();
        fail("amethod() should have thrown an exception");
    }
    catch (MySystemException e) {
        String msg = e.getMessage();
        assertTrue("bad message: " + msg, msg.equals("An error occured due to case 1 being incorrect.") || msg.equals("An error occured as case 2 could not be found"));
    }
}
甚是思念 2024-10-18 14:14:20

方法抛出的异常的声明类型是其 API 的一部分。如果您确实想要区分不同的故障模式,则应该为每种故障模式声明不同的异常类型。

所以,像这样:

/**
 * Do something.
 * @throws MySystemException1 in case 1.
 * @throws MySystemException2 if Foo not found.
 */
public void amethod() {
   // do some processing 
   if(scenario1 == true) {
      throw new MySystemException1("Case 1.");
    }
    else if(scenario2 == true) {
        throw new MySystemException2("Foo not found");
    }
}  

The declared types of exception thrown bya method are part of its API. If you really want to distinguish different failure modes, you should declare a different exception type for each failure mode.

So, something like this:

/**
 * Do something.
 * @throws MySystemException1 in case 1.
 * @throws MySystemException2 if Foo not found.
 */
public void amethod() {
   // do some processing 
   if(scenario1 == true) {
      throw new MySystemException1("Case 1.");
    }
    else if(scenario2 == true) {
        throw new MySystemException2("Foo not found");
    }
}  
森林散布 2024-10-18 14:14:20

JUnit4 中的 @Rule 解决方案:

    public class ExceptionRule implements MethodRule {
        @Override
        public Statement apply(final Statement base, final FrameworkMethod method, Object target) {
            return new Statement() {
                @Override
                public void evaluate() throws Throwable {
                    try {
                        base.evaluate();
                        Assert.fail();
                    } catch (MySystemException e) {
                         if(scenario1)
                            assertEquals("Expected error message1", e1.getMessage();
                         if(scenario2)
                            assertEquals("Expected error message2",e1.getMessage();
                }
            }
        };    
    }
}

在您的测试用例中,使用规则:

 @Rule public ExceptionRule rule = new ExceptionRule();

@Rule solution in JUnit4:

    public class ExceptionRule implements MethodRule {
        @Override
        public Statement apply(final Statement base, final FrameworkMethod method, Object target) {
            return new Statement() {
                @Override
                public void evaluate() throws Throwable {
                    try {
                        base.evaluate();
                        Assert.fail();
                    } catch (MySystemException e) {
                         if(scenario1)
                            assertEquals("Expected error message1", e1.getMessage();
                         if(scenario2)
                            assertEquals("Expected error message2",e1.getMessage();
                }
            }
        };    
    }
}

In your testcase, use the Rule:

 @Rule public ExceptionRule rule = new ExceptionRule();
兲鉂ぱ嘚淚 2024-10-18 14:14:20

JUnit 4 提供了 (Expected Exception.class)

@Test(expected= MySystemException.class) public void empty() { 
    // what ever you want
}

Google: Expected Exceptions JUnit 了解更多信息。

JUnit 4 provides (Expected Exception.class)

@Test(expected= MySystemException.class) public void empty() { 
    // what ever you want
}

Google: Expected Exceptions JUnit for more info.

谈场末日恋爱 2024-10-18 14:14:20

BDD 风格解决方案,采用 捕获异常

@Test
public void testAMethodScenario1() {

    //given scenario 1

    when(foo).amethod();

    then(caughtException())
            .isInstanceOf(MySystemException.class)
            .hasMessage("An error occured due to case 1 being incorrect.");
}

@Test
public void testAMethodScenario2() {

    //given scenario 2

    when(foo).amethod();

    then(caughtException())
            .isInstanceOf(MySystemException.class)
            .hasMessage("An error occured as case 2 could not be found");
}

源代码

依赖项

com.googlecode.catch-exception:catch-exception:1.2.0

BDD Style Solution with Catch Exception

@Test
public void testAMethodScenario1() {

    //given scenario 1

    when(foo).amethod();

    then(caughtException())
            .isInstanceOf(MySystemException.class)
            .hasMessage("An error occured due to case 1 being incorrect.");
}

@Test
public void testAMethodScenario2() {

    //given scenario 2

    when(foo).amethod();

    then(caughtException())
            .isInstanceOf(MySystemException.class)
            .hasMessage("An error occured as case 2 could not be found");
}

Source code

Dependencies

com.googlecode.catch-exception:catch-exception:1.2.0
野の 2024-10-18 14:14:20

使用 @Rule 是一个更好的解决方案,您还可以断言异常和期望消息。

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

@Test
public void aMethod_Scenario1True_ThrowsException() {
    expectedException.expect(MySystemException.class);
    expectedExcepion.expectMessage("An error occured due to case 1 being incorrect.");

    //when().thenReturn(); 
    //handle the repositories, static methods and other sub methods, if needed

    amethod();
}

@Rule 是编写异常的更优雅的方式。

A better solution with @Rule, you can assert both exception and expection message as well.

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

@Test
public void aMethod_Scenario1True_ThrowsException() {
    expectedException.expect(MySystemException.class);
    expectedExcepion.expectMessage("An error occured due to case 1 being incorrect.");

    //when().thenReturn(); 
    //handle the repositories, static methods and other sub methods, if needed

    amethod();
}

@Rule is the more elegant way to write the exception.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文