JUnit Rule

  • Rule은 ν…ŒμŠ€νŠΈ ν΄λž˜μŠ€μ—μ„œ λ™μž‘ 방식을 μž¬μ •μ˜ ν•˜κ±°λ‚˜ μ‰½κ²Œ μΆ”κ°€ν•˜λŠ” 것을 κ°€λŠ₯ν•˜κ²Œ ν•©λ‹ˆλ‹€.
  • μ‚¬μš©μžλŠ” 기쑴의 Rule을 μž¬μ‚¬μš©ν•˜κ±°λ‚˜ ν™•μž₯ν•˜λŠ” 것이 κ°€λŠ₯ν•©λ‹ˆλ‹€.

μ–΄λ–€ Rule이 μžˆμ„κΉŒ?

TemporaryFolder Rule

  • μž„μ‹œν΄λ”, νŒŒμΌλ“€μ„ 생성할 수 μžˆμŠ΅λ‹ˆλ‹€.
  • ν…ŒμŠ€νŠΈκ°€ λͺ¨λ‘ λλ‚œ ν›„ μ‚­μ œν•©λ‹ˆλ‹€.
  • 기본적으둜 resourceλ₯Ό μ‚­μ œν•˜κΈ° λͺ»ν•˜λŠ” 경우 μ–΄λ– ν•œ exception도 λ°˜ν™˜ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
public static class HasTempFolder {
  @Rule
  public final TemporaryFolder folder = new TemporaryFolder();
 
  @Test
  public void testUsingTempFolder() throws IOException {
    File createdFile = folder.newFile("myfile.txt");
    File createdFolder = folder.newFolder("subfolder");
    // ...
  }
}
  • μž„μ‹œ μž₯μ†Œμ— μ €μž₯λ˜λŠ” 것을 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.

ExternalResources Rule

  • μ™ΈλΆ€ Resource(DB Connection, File, Socket) μ΄ˆκΈ°ν™” / λ°˜ν™˜μ„ κ΄€λ¦¬ν•©λ‹ˆλ‹€.
  • νŠΉμ • μžμ›μ„ λ‹€λ₯Έ ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€μ—μ„œ μž¬μ‚¬μš©ν•  λ•Œ μœ μš©ν•©λ‹ˆλ‹€.
public static class UsesExternalResource {
  Server myServer = new Server();
 
  @Rule
  public final ExternalResource resource = new ExternalResource() {
    @Override
    protected void before() throws Throwable {
      myServer.connect();
    };
 
    @Override
    protected void after() {
      myServer.disconnect();
    };
  };
 
  @Test
  public void testFoo() {
    new Client().run(myServer);
  }
}

ErrorCollector Rule

  • μ—λŸ¬κ°€ λ°œμƒν•˜λ”λΌλ„ μ§€μ†μ μœΌλ‘œ ν…ŒμŠ€νŠΈλ₯Ό μ§„ν–‰ν•˜κ²Œ λ„μ™€μ£ΌλŠ” Ruleμž…λ‹ˆλ‹€.
public static class UsesErrorCollectorTwice {
  @Rule
  public final ErrorCollector collector = new ErrorCollector();
 
  @Test
  public void example() {
    collector.addError(new Throwable("first thing went wrong"));
    collector.addError(new Throwable("second thing went wrong"));
  }
}
  • Testλ₯Ό μ§„ν–‰ν•˜λ©΄μ„œ λ°œμƒν–ˆλ˜ λͺ¨λ“  Error κ²°κ³Όλ₯Ό λ°›μ•„ λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€.

Verifier Rule

  • ν…ŒμŠ€νŠΈ 자체λ₯Ό κ²€μ¦ν•˜λŠ” assertμ™€λŠ” λ‹€λ₯΄κ²Œ, ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€ μ‹€ν–‰ ν›„ λ§Œμ‘±ν•΄μ•Όν•˜λŠ” ν™˜κ²½μ‘°κ±΄μ΄λ‚˜ Global쑰건(κ°μ²΄λ“€μ˜ μ’…ν•© μƒνƒœ)을 κ²€μ‚¬ν•˜λŠ”λ° μ‚¬μš©λ©λ‹ˆλ‹€.
public static class UsesVerifier {
 
  private static String sequence;
 
  @Rule
  public final Verifier collector = new Verifier() {
    @Override
    protected void verify() {
      sequence += "verify ";
    }
  };
 
  @Test
  public void example() {
    sequence += "test ";
  }
 
  @Test
  public void verifierRunsAfterTest() {
    sequence = "";
    assertThat(testResult(UsesVerifier.class), isSuccessful());
    assertEquals("test verify ", sequence);
  }
}

TestWatcher

  • ν…ŒμŠ€νŠΈ Interceptor (starting, succeeded, failed, finished…)
  • AOP와 λΉ„μŠ·ν•œ 역할을 ν•˜λŠ” κ²ƒμœΌλ‘œ λ³΄μž…λ‹ˆλ‹€.
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 WatchermanTest {
	private static String watchedLog = "";
 
	@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) {
			watchedLog += description.getDisplayName() + " " + "success!\n";
		}
 
		@Override
		protected void failed(Throwable e, Description description) {
			watchedLog += description.getDisplayName() + " " + e.getClass().getSimpleName() + "\n";
		}
 
		@Override
		protected void skipped(AssumptionViolatedException e, Description description) {
			watchedLog += 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(watchedLog);
	}
 
	@Test
	public void fails() {
		fail();
	}
 
	@Test
	public void test_success() {
	}
}
  • ν…ŒμŠ€νŠΈ 정보λ₯Ό λ‚¨κΈ°λŠ” μ½”λ“œλ₯Ό λΆ„λ¦¬ν•˜μ—¬ 기둝할 수 μžˆμŠ΅λ‹ˆλ‹€.

TestName

  • ν…ŒμŠ€νŠΈ λ©”μ†Œλ“œλͺ…을 얻을 수 μžˆμŠ΅λ‹ˆλ‹€.
public class NameRuleTest {
  @Rule
  public final TestName name = new TestName();
 
  @Test
  public void testA() {
    assertEquals("testA", name.getMethodName());
  }
 
  @Test
  public void testB() {
    assertEquals("testB", name.getMethodName());
  }
}

Timeout

  • ν•˜λ‚˜μ˜ ν…ŒμŠ€νŠΈκ°€ ν†΅κ³Όν•˜κΈ° μœ„ν•œ timeout μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€. (vs @Timeout)
public static class HasGlobalTimeout {
  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";
    for(;;) {}
  }
}

ExpectedException

  • μ˜ˆμ™Έ 직접 확인할 수 μžˆμŠ΅λ‹ˆλ‹€. (vs @Expected)
  • Error λ©”μ‹œμ§€λ„ 검증이 κ°€λŠ₯ν•©λ‹ˆλ‹€.
public static class HasExpectedException {
  @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() {
    thrown.expect(NullPointerException.class);
    thrown.expectMessage("happened?");
    thrown.expectMessage(startsWith("What"));
    throw new NullPointerException("What happened?");
  }
}

ClassRule

  • TestSuite의 ν΄λž˜μŠ€λ§ˆλ‹€ μ μš©ν•  수 μžˆλŠ” Ruleμž…λ‹ˆλ‹€.
@RunWith(Suite.class)
@SuiteClasses({A.class, B.class, C.class})
public class UsesExternalResource {
  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();
    };
  };
}

RuleChain

  • μ—¬λŸ¬κ°œμ˜ Rule chaining으둜 μ μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
public class UseRuleChain {
    @Rule
    public final TestRule chain = RuleChain
                           .outerRule(new LoggingRule("outer rule"))
                           .around(new LoggingRule("middle rule"))
                           .around(new LoggingRule("inner rule"));
 
    @Test
    public void example() {
        assertTrue(true);
    }
}

Custom Rule

System Rule

Reference