Testing Flutter apps翻譯-單元測試簡介

o動感超人o發表於2019-04-19

官方文件

在某些情況下,單元測試依賴的類可能從實時Web服務或資料庫中獲取資料。這時可能很不方便,原因如下:

  • 呼叫實時服務或資料庫會減慢測試的執行速度。
  • 如果Web服務或資料庫返回意外結果,則曾經通過的測試可能會失敗。這被稱為“不可靠的測試”。
  • 很難使用實時Web服務或資料庫測試所有可能的成功和失敗場景。

所以,與其依賴實時的web服務或者資料庫,不如你“mock”這些依賴。mock允許我們模擬一個實時的web服務或者資料庫並且根據情況返回特定結果。

一般來說,你可以通過建立類的替代實現來模擬依賴項。你可以自己寫這些替代實現或者使用更便捷的Mockito package

下面的步驟講解了使用Mockito package的基礎操作,更多操作請檢視Mockito package documentation

步驟

  1. 新增 mockito 和 test 依賴。
  2. 建立一個方法用來測試。
  3. 建立一個模擬http.Client的測試檔案。
  4. 為每個條件編寫測試。
  5. 執行測試。

1. 新增 mockito 和 test 依賴。

要想使用 mockito package,你首先需要新增它和 flutter_testpubspec.yaml 檔案裡,新增位置在dev_dependencies下面。

你也可以使用 http package,在dependencies下面新增該依賴即可。

dependencies:
  http: <newest_version>
dev_dependencies:
  test: <newest_version>
  mockito: <newest_version>
複製程式碼

2. 建立一個方法用來測試。

在本例中,你將對從Internet方法獲取資料的fetchpost函式進行單元測試。為了測試這個函式,你需要做如下2點改變:

  1. 提供一個http.Client引數給函式。這允許你根據情況提供正確的http.Client。對於Flutter和服務端專案,你可以提供http.IOClient。對於瀏覽器應用程式,你可以提供http.BrowserClient。對於單元測試,你可以提供模擬的http.Client。

2.使用提供的client從網路獲取資料,而不是直接使用http.get方法,否則會很難模擬資料。

這個測試函式看起來應該是這樣的:

Future<Post> fetchPost(http.Client client) async {
  final response =
      await client.get('https://jsonplaceholder.typicode.com/posts/1');

  if (response.statusCode == 200) {
    // If the call to the server was successful, parse the JSON
    return Post.fromJson(json.decode(response.body));
  } else {
    // If that call was not successful, throw an error.
    throw Exception('Failed to load post');
  }
}
複製程式碼

3. 建立一個模擬http.Client的測試檔案。

下一步,建立一個測試檔案和一個 MockClient 類。根據單元測試介紹中的建議,在根目錄的 test 資料夾下建立一個叫 fetch_post_test.dart 的檔案。

這個 MockClient 類實現了 http.Client。這將允許你將 MockClient 作為引數傳遞到 fetchPost 函式,並且允許你在每個測試裡返回不同的結果。

// Create a MockClient using the Mock class provided by the Mockito package.
// Create new instances of this class in each test.
class MockClient extends Mock implements http.Client {}

main() {
  // Tests go here
}
複製程式碼

4. 為每個條件編寫測試。

如果你思考一下 fetchPost 函式,會想到它只能返回下面的2個結果中的一個:

  1. 如果獲取資料成功,會返回一個Post資料。
  2. 如果獲取資料失敗,會丟擲一個異常。

因此,你想要測試這兩個結果。你可以使用 MockClient 返回獲取資料成功的測試結果,也可以返回一個獲取資料失敗的測試結果。

為了實現這一點,我們使用Mockito提供的when函式。

// Create a MockClient using the Mock class provided by the Mockito package.
// Create new instances of this class in each test.
class MockClient extends Mock implements http.Client {}

main() {
  group('fetchPost', () {
    test('returns a Post if the http call completes successfully', () async {
      final client = MockClient();

      // Use Mockito to return a successful response when it calls the
      // provided http.Client.
      when(client.get('https://jsonplaceholder.typicode.com/posts/1'))
          .thenAnswer((_) async => http.Response('{"title": "Test"}', 200));

      expect(await fetchPost(client), isInstanceOf<Post>());
    });

    test('throws an exception if the http call completes with an error', () {
      final client = MockClient();

      // Use Mockito to return an unsuccessful response when it calls the
      // provided http.Client.
      when(client.get('https://jsonplaceholder.typicode.com/posts/1'))
          .thenAnswer((_) async => http.Response('Not Found', 404));

      expect(fetchPost(client), throwsException);
    });
  });
}
複製程式碼

5. 執行測試。

既然你現在寫好了fetchPost的單元測試,那麼就可以執行它了。

 dart test/fetch_post_test.dart
複製程式碼

你也可以使用單元測試介紹裡介紹過的你喜歡的編譯器裡執行測試

總結:

在這個例子裡,你已經學會了如何使用Mockito去測試依賴web伺服器或者資料庫的函式或者類。這只是一個簡短的 Mockito library 和模擬概念的介紹。更多資訊請檢視 Mockito package

相關文章