Cucumber JVMを使用しているときに正しい例外がスローされることをテストするにはどうすればよいですか? JUnitを使用するときは、次のようにします。
@Test(expected = NullPointerException.class)
public void testExceptionThrown(){
taskCreater.createTask(null);
}
ご覧のとおり、これは非常にエレガントです。しかし、キュウリ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);
}
フラグにtry
..catch
の後にassertTrue
が続く必要があることに注意してください。
不幸な道をテストするのは難しいかもしれません。これがキュウリでそれをするために私が見つけた素晴らしい方法です。
Scenario: Doing something illegal should land you in jail
Then a failure is expected
When you attempt something illegal
And it fails.
OK、Then
の前にWhen
を置いたので、撃たないでください。読みやすくなると思いますが、そうする必要はありません。
例外を(キュウリスコープの)ワールドオブジェクトに保存しますが、ステップファイルで保存することもできますが、これにより後で制限されます。
public class MyWorld {
private boolean expectException;
private List<RuntimeException> exceptions = new ArrayList<>();
public void expectException() {
expectException = true;
}
public void add(RuntimeException e) {
if (!expectException) {
throw e;
}
exceptions.add(e);
}
public List<RuntimeException> getExceptions() {
return exceptions;
}
}
その場合、手順は非常に簡単です。
@Then("a failure is expected")
public void a_failure_is_expected() {
myWorld.expectException();
}
(少なくとも時々)例外を予期しているステップで、それをキャッチして世界に追加します。
@When("you attempt something illegal")
public void you_attempt_something_illegal() {
try {
myService.doSomethingBad();
} catch (RuntimeException e) {
world.add(e);
}
}
これで、例外がワールドで記録されたかどうかを確認できます。
@And("it fails")
public void it_fails() {
assertThat(world.getExceptions(), is(not(empty()));
}
このアプローチの最も価値のあることは、予期しないときに例外を飲み込まないことです。
次のように、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);
}
動作テストは、プロジェクトが仕様に準拠しているかどうかを検証します。ユーザーがシステムの使用中にNullPointerExceptionを予期しているとは思えません。
私の意見では(私はあなたのプロジェクトに精通していません)、例外は予期しないエラーやユーザーのミスに対応しているため、ユニットテスト中にのみチェックする必要があります。
動作テスト中に例外をチェックすることは非常に珍しいことです。テスト中に例外がスローされた場合、失敗するはずです。
例えば:
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 */
私の単体テストでは、次のようになります。
@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();
}
キュウリを使用したことはありませんが、
public void null_exception_thrown() {
try {
taskCreater.createTask(null);
fail("Null Pointer Expected");
} catch (NullPointerException e) {
// Do Nothing
}
}
あなたのために働きますか?
以前は、機能の手順で例外名を予期していました。電卓のテスト例
これが除算例外の機能ファイルエントリです:
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
ご覧のとおり、例外名を追加しました。したがって、ステップ定義で、例外の名前を取得します。
ここで、ゼロ除算のときに例外を取得して変数を入力する必要があります。そして、この変数を取得して、そのクラス名(例外名)を比較します
したがって、ゼロ除算を行うステップ定義では
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;
}
}
そして、例外を検証するためのステップ定義が必要です
@Then("^I got Exception (.+)")
public void iGotArithmeticException(String aException) throws Throwable {
Assert.assertEquals("Exception MissMatch",aException,actualException.getClass().getSimpleName());
}
完全なプロジェクトはここで見ることができます: キュウリのステップ
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);
}
Cucumberは、その場合のように、低レベルの単体テストよりも高レベルの受け入れテストをテストすることを目的としていると思います動作とは反対の構造をテストしますこれはCucumberフレームワークの望ましい使用法ではありません。