반응형
JUnit Rule이란 ?
JUnit Rule은 테스트 케이스를 실행하기 전/후에 추가 코드를 실행할 수 있도록 도와준다.
즉,@Before와 @After로 선언된 메서드에서도 실행 전후처리로 코드를 넣을 수 있지만,
JUnit Rule로 작성하면 재사용하거나 더 확장 가능한 기능으로 개발할 수 있는 장점이 있다.
즉, 요약하자면
- Rule은 테스트 클래스에서 동작 방식을 재정의 하거나 쉽게 추가하는 것을 가능하게 한다.
- 사용자는 기존의 Rule을 재사용하거나 확장하는 것이 가능해진다.
Rule의 종류
1. TemporaryFoler Rule
- 임시 폴더, 파일들을 생성할 수 있다.
- 테스트가 모두 끝난 후 삭제한다.
- 기본적으로 resource를 삭제하지 못하는 경우 어떠한 exception도 반환하지 않는다.
package com.example.myapplication; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import java.io.File; import java.io.IOException; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; public class MyTest { @Rule public final TemporaryFolder folder = new TemporaryFolder(); @Test public void testUsingTempFolder() throws IOException { File createdFile = folder.newFile("myfile.txt"); File createdFolder = folder.newFolder("subfolder"); System.out.println(createdFile); System.out.println(createdFolder); assertThat(2, is(folder.getRoot().list().length)); } }

2. ExternalResources Rule
- 외부 Resource(DB Connection, File, Socket) 초기화 / 반환을 관리한다.
- 특정 자원을 다른 테스트 케이스에서 재사용할 때 유용하다.
package com.example.myapplication; import org.junit.AfterClass; import org.junit.AssumptionViolatedException; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExternalResource; public class MyTest { private Server myServer = new Server(); @Rule public final ExternalResource resource = new ExternalResource() { @Override protected void before() { myServer.connect(); } @Override protected void after() { myServer.disconnect(); } }; @Test public void serverTest() { System.out.println("Server test"); } public static class Server { public void connect() { System.out.println("connect..."); } public void disconnect() { System.out.println("disconnect..."); } } }

3. ErrorCollector Rule
- 에러가 발생하더라도 지속적으로 테스트를 진행하게 도와주는 Rule이다.
package com.example.myapplication; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ErrorCollector; public class MyTest { public static class UsesErrorCollectorTwice { @Rule public final ErrorCollector collector = new ErrorCollector(); @Test public void errorTest() { collector.addError(new Throwable("first thing went wrong")); collector.addError(new Throwable("second thing went wrong")); } } }

4. Verifier Rule
- 테스트 자체를 검증하는 assert와는 다르게, 테스트 케이스 실행 후 만족해야하는 환경조건이나 Global조건(객체들의 종합 상태)을 검사하는데 사용된다.
package com.example.myapplication; import org.junit.Rule; import org.junit.Test; import org.junit.rules.Verifier; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; public class MyTest { private static String mSequence = ""; @Rule public final Verifier collector = new Verifier() { @Override protected void verify() { mSequence += "Verify"; System.out.println("verify : " + mSequence); } }; @Test public void example() { mSequence += "test"; System.out.println("example : " + mSequence); assertThat("test", is(mSequence)); } @Test public void verifierRunsAfterTest1() { System.out.println("verifierRunsAfterTest1 : " + mSequence); assertThat("testVerify", is(mSequence)); } @Test public void verifierRunsAfterTest2() { System.out.println("verifierRunsAfterTest2 : " + mSequence); assertThat("testVerifyVerify", is(mSequence)); } }

해당 코드를 보면 하나의 test를 진행할 때마다
Rule의 Verify 메서드가 호출됨을 알 수 있다.
5. TestWatcher
- 테스트 Interceptor (starting, succeeded, failed , finished)을 intercept한다.
package com.example.myapplication; import org.junit.AfterClass; import org.junit.AssumptionViolatedException; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestRule; import org.junit.rules.TestWatcher; import org.junit.runner.Description; import org.junit.runners.model.Statement; import static org.junit.Assert.fail; public class MyTest { private static String mWatchedLog = ""; @Rule public final TestRule watchman = new TestWatcher() { @Override public Statement apply(Statement base, Description description) { return super.apply(base, description); } @Override protected void succeeded(Description description) { mWatchedLog += description.getDisplayName() + " " + "success!\n"; } @Override protected void failed(Throwable e, Description description) { mWatchedLog += description.getDisplayName() + " " + e.getClass().getSimpleName() + "\n"; } @Override protected void skipped(AssumptionViolatedException e, Description description) { mWatchedLog += description.getDisplayName() + " " + e.getClass().getSimpleName() + "\n"; } @Override protected void starting(Description description) { super.starting(description); } @Override protected void finished(Description description) { super.finished(description); } }; @AfterClass public static void teardown(){ System.out.println("===== Show Logs ====="); System.out.println(mWatchedLog); } @Test public void fails() { fail(); } @Test public void test_success() { fail("test_success fail"); } }

6. TestName
- 테스트 메소드명을 얻을 수 있다.
package com.example.myapplication; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestName; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; public class MyTest { @Rule public final TestName name = new TestName(); @Test public void testA() { assertThat("testA", is(name.getMethodName())); } @Test public void testB() { assertThat("testB", is(name.getMethodName())); } }

7. Timeout
- 하나의 테스트가 통과하기 위한 timeout 설정할 수 있다. (vs @Timeout)
package com.example.myapplication; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestName; import org.junit.rules.TestRule; import org.junit.rules.Timeout; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; public class MyTest { public static String log; @Rule public final TestRule globalTimeout = Timeout.millis(20); @Test public void testInfiniteLoop1() { log += "ran1"; for(;;) {} } @Test public void testInfiniteLoop2() { log += "ran2"; } }

8. ExpectedException
- 예외 직접 확인할 수 있다. (vs @Expected)
- Error 메시지도 검증이 가능하다.
package com.example.myapplication; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import static org.hamcrest.core.StringStartsWith.startsWith; public class MyTest { @Rule public final ExpectedException thrown = ExpectedException.none(); @Test public void throwsNothing() { } @Test public void throwsNullPointerException() { thrown.expect(NullPointerException.class); throw new NullPointerException(); } @Test public void throwsNullPointerExceptionWithMessage() { // NullPointerException이고 // happend가 포함되고 What로 시작하는 exception message 여야한다. thrown.expect(NullPointerException.class); thrown.expectMessage("happened?"); thrown.expectMessage(startsWith("What")); // throw new NullPointerException("What happened?"); } }

9. ClassRule
- TestSuite의 클래스마다 적용할 수 있는 Rule입니다.
package com.example.myapplication; import org.apache.maven.settings.Server; import org.junit.ClassRule; import org.junit.rules.ExternalResource; @RunWith(Suite.class) @SuiteClasses({A.class, B.class}) public class MyTest { public static final Server myServer = new Server(); @ClassRule public static final ExternalResource resource = new ExternalResource() { @Override protected void before() throws Throwable { myServer.connect(); }; @Override protected void after() { myServer.disconnect(); }; }; }

출처
https://junit.org/junit4/javadoc/4.12/org/junit/ClassRule.html
https://beomseok95.tistory.com/300
https://nesoy.github.io/articles/2018-12/Junit-Rule
반응형
'Applied > Unit Test' 카테고리의 다른 글
Spy에 대한 몇가지 예제 (0) | 2021.02.07 |
---|---|
블랙박스 테스트, 화이트박스 테스트 개념 (0) | 2020.04.27 |
[Robolectric] robolectric shadow bitmap 관련 참고 코드 (0) | 2020.04.21 |
[Robolectric] Robolectric을 이용한 Parameterized testing (0) | 2020.04.17 |
[JUnit] exception 테스트 하는 방법 (0) | 2020.03.01 |