[深刻JUnit] @Before, @After, @Test的祕密

最近對JUnit和Mockito的內部實現比較感興趣,將在接下來的一段時間,和你們一塊兒深刻代碼細節。html

王侯將相,寧有種乎 (JUnit也沒啥Magic吧)java

閱讀前提android

  • 據說過Java Annotationsegmentfault

  • 使用過JUnitmaven

  • 知道@Before, @After, @Testide

  • 對JUnit的內部實現有興趣函數

代碼版本: junit 4.12
代碼搜索工具: http://grepcode.com/
經常使用符號工具

  • _: 用來略去代碼段中可有可無的parameter測試

  • ...: 用來略去可有可無的代碼實現spa

Example

下面是一個很簡單的JUunit Test Class

public class SampleTest {
   @Before
   protected void setUp(){ ... }

   @Test
   public void test1(){ ... }       
   
   @After
   public void tearDown(){ ... }
}

本文要解答的問題:@Before, @Test, @After如何影響test workflow的?

Q&A

Q1. 如何提取一個函數的Annotation信息?
A: 任何Java提供了Method::getDeclaredAnnotations()

Q2. 如何把SampleTest裏的methods都羅列出來?
A: Java提供了Class::getDeclaredMethods()

Q3: @Before, @Test, @After的執行順序如何保證的?
A: 在junit的BlockJUnit4ClassRunner class中有一段代碼:

Statement statement = methodInvoker(method, _);
statement = withBefores(method, _, statement);
statement = withAfters(method, _, statement);

http://grepcode.com/file/repo1.maven.org...

Statement能夠看作是一個函數封裝(Functional Interface),內部只有一個execute()函數。method是被@Test修飾的測試函數(本例中的test1()),withBeforesSampleClass中被@Before修飾的全部函數找出來,而後封裝成一個新的Statement

//好比說,能夠用下面的naive實現
void withBefores(Method m, _, Statement statement) {
  // 利用Q1和Q2的知識點把@Before修飾的函數都找出來
  List<Method> befores = ...
  return new Statement{
    @Override
    public execute() {
      for (Method b : befores) {
        b.execute();
      }
      m.execute();
    }
  }
}

Q4: Q3中的BlockJUnit4ClassRunnerSampleTest攪合到一塊兒的?
A: 請本身去看BlockJUnit4ClassRunner的constructor的parameter是什麼。

Summary

  • 利用Java原生的getDeclaredAnnotationsgetDeclaredMethods,能夠輕鬆地獲得測試類SampleTest中函數的annotations。

  • JUnit用一個Statement來作把setUp()test1(),以及tearDown()封裝到一塊兒,並保證其執行順序。

References

下期內容

BlockJUnit4ClassRunner又被誰調用了呢?
運行unit test的入口在哪裏?
請看:[深刻JUnit] 測試運行的入口
clipboard.png

相關文章
相關標籤/搜索