Cucumber JVM:测试是否抛出了正确的exception

我有点惊讶,我无法在网上找到这个问题的答案。 无论如何,当使用Junit来测试抛出正确的exception时,我会做这样的事情:

@Test(expected = NullPointerException.class) public void testExceptionThrown(){ taskCreater.createTask(null); } 

正如您在上面所看到的,如果抛出exception,它是一种非常优雅的测试方法,但是当使用黄瓜JVM时,如何实现同样的优雅呢? 我的测试现在看起来像这样:

 @Then("the user gets a Null pointer exception$") public void null_exception_thrown() { boolean result = false; try { taskCreater.createTask(null); } catch (NullPointerException e) { result = true; } assertTrue(result); } 

这太丑了!!

测试不快乐的路径可能很难。 这是一个很好的方式,我发现用黄瓜做。

 Scenario: Doing something illegal should land you in jail Then a failure is expected When you attempt something illegal And it fails. 

好吧,不要拍我,因为我把时间Then到了When ,我认为它看起来更好,但你不必这样做。

我将我的例外存储在(黄瓜范围的)世界对象中,但您也可以在步骤文件中执行此操作,但这将限制您以后的使用。

 public class MyWorld { private boolean expectException; private List exceptions = new ArrayList<>(); public void expectException() { expectException = true; } public void add(RuntimeException e) { if (!expectException) { throw e; } exceptions.add(e); } public List getExceptions() { return exceptions; } } 

您的步骤非常简单:

 @Then("a failure is expected") public void a_failure_is_expected() { myWorld.expectException(); } 

在您(至少有时)期待exception的步骤中,抓住它并将其添加到世界中。

 @When("you attempt something illegal") public void you_attempt_something_illegal() { try { myService.doSomethingBad(); } catch (RuntimeException e) { world.add(e); } } 

现在,您可以检查是否在世界中记录了exception。

 @And("it fails") public void it_fails() { assertThat(world.getExceptions(), is(not(empty())); } 

这种方法最有价值的地方在于,当你不期望它时,它不会吞下exception。

您是否尝试过使用带有ExpectedException的junit @Rule注释,如下所示:

 @Rule public ExpectedException expectedEx = ExpectedException.none(); @Then("the user gets a Null pointer exception$") public void null_exception_thrown() { expectedEx.expect(NullPointerException.class); //expectedEx.expectMessage("the message"); taskCreater.createTask(null); } 

从未使用黄瓜,但会

  public void null_exception_thrown() { try { taskCreater.createTask(null); fail("Null Pointer Expected"); } catch (NullPointerException e) { // Do Nothing } } 

为你工作?

行为测试validation您的项目是否遵循规范,我怀疑用户在使用系统时是否期望NullPointerException。

在我看来(我不熟悉你的项目),只应在unit testing期间检查exception,因为它们对应于意外错误或用户错误。

在行为测试期间检查exception是非常不寻常的。 如果在测试期间抛出exception,则应该失败。

例如:

test.feature

 Given that I have a file "users.txt" And I try to import users /* If an Exception is thrown here, the test fails */ Then I should see the following users: /* list of users */ 

在我的unit testing中,我会:

 @Test(expected = MyException.class) public void importUsersShouldThrowMyExceptionWhenTheFileIsNotFound() { // mock a call to a file and throw an exception Mockito.when(reader.readFile("file.txt").thenThrow(new FileNotFoundException()); importer.importUsers(); } 

我相信Cucumber的目的是测试更高级别的验收测试而不是低级别的unit testing,因为在这种情况下, 我们将测试与不是 Cucumber框架的期望用途的行为相对的结构

我建议你使用org.assertj.assertj-core

感谢Assertions类,您可以像下面这样简化断言:

 @Then("the user gets a Null pointer exception$") public void null_exception_thrown() { Assertions.assertThatThrownBy(() -> taskCreater.createTask(null)). isInstanceOf(NullPointerException.class); } 

我以前在function步骤中有预期的exception名称。 对于计算器测试示例

这是我的除法exception的function文件条目:

 Scenario: Dividing a number with ZERO Given I want to test calculator When I insert 5.5 and 0.0 for division Then I got Exception ArithmeticException 

所以,您可能会看到,我已添加了例外名称。 所以,在步骤定义中,我得到了exception的名称。

现在,我们需要在除以ZERO并输入变量时获得exception。 并获取此变量以比较其类名(exception名称)

所以,在步骤定义中,除以零

 private Exception actualException; @When("^I insert (.+) and (.+)for division$") public void iInsertAndForDivision(double arg0, double arg1) throws Throwable { try { result = calculator.div(arg0, arg1); } catch (Exception e) { actualException =e; } } 

我需要步骤定义来validationexception

  @Then("^I got Exception (.+)") public void iGotArithmeticException(String aException) throws Throwable { Assert.assertEquals("Exception MissMatch",aException,actualException.getClass().getSimpleName()); } 

完整的项目可以在这里看到: 黄瓜的步骤