Đôi khi chúng ta gặp một số vấn đề ngoài ý muốn khi thực thi Unit test như lỗi kết nối internet, kết nối database, thiếu tài nguyên, … dẫn đến test case của chúng ta bị fail. Trong những trường hợp đó, chúng ta mong muốn có thể thực thi lại các test case một cách tự động. Nhưng bằng cách nào chúng ta có thể làm được điều này với JUnit? Chúng ta sẽ cùng tìm hiểu trong phần tiếp theo của bài viết này.
Nội dung
Làm thế nào để chạy lại một failed Test trong JUnit?
Trong bài viết Đơn giản hóa Unit Test với JUnit Rule tôi đã giới thiệu với các bạn về Rule trong JUnit, cách sử dụng các Rule được hỗ trợ sẵn trong JUnit và cách tự viết một Rule.
Đối với tình huống này, chúng ta có thể tự viết một custom Rule implements một class TestRule và override phương thức evaluate() để viết code xử lý retry test mỗi khi test bị fail.
Ví dụ Retry Failed Tests trong JUnit
Tạo custom Rule để cố gắng thực thi với một số lần được chỉ định (numberOfRetryTimes) và xác định thời gian chờ trước khi thử lại (delayInMiliseconds).
package com.gpcoder.junit.retry; import java.util.concurrent.TimeUnit; import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runners.model.Statement; public class RetryRule implements TestRule { private int numberOfRetryTimes; private int delayInMiliseconds; public RetryRule(int numberOfRetryTimes, int delayInMiliseconds) { this.numberOfRetryTimes = numberOfRetryTimes; this.delayInMiliseconds = delayInMiliseconds; } public Statement apply(Statement base, Description description) { return statement(base, description); } private Statement statement(final Statement base, final Description description) { System.out.println(String.format("\nExecuting test: %s()", description.getMethodName())); return new Statement() { @Override public void evaluate() throws Throwable { Throwable caughtThrowable = null; // Implement retry logic here for (int i = 0; i < numberOfRetryTimes; i++) { try { base.evaluate(); return; } catch (Throwable t) { caughtThrowable = t; System.out.println(String.format("%s : run %d failed.", description.getDisplayName(), (i + 1))); } delay(delayInMiliseconds); } System.out.println(String.format("%s : giving up after %d failures.\n", description.getDisplayName(), numberOfRetryTimes)); throw caughtThrowable; } }; } private static void delay(int delayInMiliseconds) throws InterruptedException { System.out.println("Waiting for retry next time"); TimeUnit.MICROSECONDS.sleep(delayInMiliseconds); } }
Viết class test bao gồm 2 phương thức:
- getData() : phương thức này được thực thi thành công sau khi thử lại 2 lần.
- alwaysFailed(): phương thức này thực thi luôn bị fail.
package com.gpcoder.junit.retry; import static org.junit.Assert.assertEquals; import java.net.ConnectException; import org.junit.Rule; import org.junit.Test; class ThirdPartyApi { private static int retryCall = 0; public static String getData() throws ConnectException { if (retryCall < 2) { retryCall++; throw new ConnectException("Cannot retrieve data. Please try again"); } return "gpcoder.com"; } public static String alwaysFailed() throws ConnectException { if (true) { throw new ConnectException("Cannot retrieve data. Please try again"); } return "gpcoder.com"; } } public class RetryRuleTest { @Rule public RetryRule retryRule = new RetryRule(3, 10); @Test public void getDataTest() throws ConnectException { assertEquals("gpcoder.com", ThirdPartyApi.getData()); } @Test public void alwaysFailedTest() throws ConnectException { assertEquals("gpcoder.com", ThirdPartyApi.alwaysFailed()); } }
Kết quả test:
Executing test: alwaysFailedTest() alwaysFailedTest(com.gpcoder.junit.retry.RetryRuleTest) : run 1 failed. Waiting for retry next time alwaysFailedTest(com.gpcoder.junit.retry.RetryRuleTest) : run 2 failed. Waiting for retry next time alwaysFailedTest(com.gpcoder.junit.retry.RetryRuleTest) : run 3 failed. Waiting for retry next time alwaysFailedTest(com.gpcoder.junit.retry.RetryRuleTest) : giving up after 3 failures. Executing test: getDataTest() getDataTest(com.gpcoder.junit.retry.RetryRuleTest) : run 1 failed. Waiting for retry next time getDataTest(com.gpcoder.junit.retry.RetryRuleTest) : run 2 failed. Waiting for retry next time