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