---
tags: Microservice Pattern, Microservice
---
# Testing microservices: Part 1
傳統軟體開發進入測試階段後,會交給QA負責,而QA大部分是透過人工方式測試,這樣的測試是很沒效率的:
* 人工測試很沒效率
* 僅在軟體開發完成後才測試是不夠的
-> 撰寫階段自動測試
## 9.1 Testing strategies for microservice architectures
> have **automated tests** that you can run **during development**.
ex. 設計一鍵測試機制,僅需幾秒就能測試完成:
* 如何撰寫測試程式
* 如何拿捏測試細膩度
### 9.1.1 Overview of testing
測試定義:
> A test case is a set of test inputs, execution conditions, and expected results developed for a particular objective, such as to exercise a particular program path or to verify compliance with a specific requirement.

#### WRITING AUTOMATED TESTS
Automated tests通常透過testing framework開發(ex. JUnit -> Java testing framework)。
automated test由四個步驟組成:
* Setup:
初始化test fixture(包含SUT及其他會用到部分)
* Execute:
調用(測試)SUT
* Verify:
由調用結果驗證SUT
* Teardown:
清除fixture中測試資料

#### TESTING USING MOCKS AND STUBS
SUT間常有相依性(dependencies),但各SUT測試複雜度、速度不一,整合測試會造成測試緩慢、誤判測試的結果等問題 -> test an SUT in isolation
test double:

test doubles有兩種類型:
* stubs:
returns values to the SUT
* mocks:
a test uses to verify that the SUT correctly invokes a dependency
> mock is often a stub.
[test double介紹1](http://teddy-chen-tw.blogspot.com/2014/09/test-double1.html)
[test double介紹2](http://teddy-chen-tw.blogspot.com/2014/09/test-double2.html)
#### THE DIFFERENT TYPES OF TESTS
> this chapter focus on automated tests that verify the **functional aspects** of the application or service.
* Unit tests:
Test a **small part** of a service, such as a class.
* Integration tests:
Verify that a service can interact **with infrastructure services** such as databases and other application services.
* Component tests:
Acceptance tests for **an individual service**.
* End-to-end tests:
Acceptance tests for the **entire application**.
依scope區分測試只是其中一種方法,另一種方法為象限測試(quadrant).
#### USING THE TEST QUADRANT TO CATEGORIZE TESTS
[Brian Marick’s test quadrant](http://www.exampler.com/old-blog/2003/08/21/#agile-testing-project-1):

* Q1—Support programming/technology facing:
unit and integration tests
* Q2—Support programming/business facing:
component and end-to-end test
* Q3—Critique application/business facing:
usability and exploratory testing
* Q4—Critique application/technology facing:
nonfunctional acceptance tests such as performance tests
[Testing Quadrants](https://kojenchieh.pixnet.net/blog/post/75411628)
#### USING THE TEST PYRAMID AS A GUIDE TO FOCUSING YOUR TESTING EFFORTS
[test pyramid](https://martinfowler.com/bliki/TestPyramid.html):
越下層的測試越簡單、快速,可大量測試,反之,越上層的測試越複雜、慢,無法大量測試。

### 9.1.2 The challenge of testing microservices
IPC對於microservice相當重要,第三章提到很多種IPC溝通方式,在系統上可能會交錯使用。

> * REST client -> service:
The API gateway routes requests to services and implements API composition.
> * Domain event consumer -> publisher:
Order History Service consumes events published by Order Service.
> * Command message requestor -> replier:
Order Service sends command messages to various services and consumes the replies.
每個interaction都是兩端的agreement或contract,不應該為了修正一端的bug而改動 -> stable APIs
驗證兩端service時最簡單的方式為直接串起來測試(end-to-end),但可能會需要依賴其他service傳遞(transitive dependencies)。較好的驗證方式為**consumer-driven contract testing**
#### CONSUMER-DRIVEN CONTRACT TESTING
在consumer contract test中,通常service間有**consumer-provider relationship**(Ex.API gateway=consumer,Order service=provider)
consumer contract test主要是藉由不同consumer來測試provider,且只聚焦於**shape**上。
以REST endpoint為例,consumer contract test僅測試:
* Has the expected HTTP method and path
* Accepts the expected headers, if any
* Accepts a request body, if any
* Returns a response with the expected status code, headers, and body

實務上常用Spring Cloud Contract撰寫consumer contract tests
#### TESTING SERVICES USING SPRING CLOUD CONTRACT
值得使用的contract testing framework:
[Spring Cloud Contract](https://cloud.spring.io/spring-cloud-contract/reference/html/)
[Pact family of frameworks](https://github.com/pact-foundation)
Spring Cloud Contract有以下特色:
* 提供Groovy domain-specific language(DSL)撰寫contracts
* 每個contract都是實體的interaction(Ex. HTTP request and response)
* configures mocks(Ex. mock HTTP server)
測試流程如下:

contract範例:

#### CONSUMER CONTRACT TESTS FOR MESSAGING APIS
除了REST client外,也會有透過asynchronous request/response方式溝通的client,Spring Cloud Contract提供request message與response message來處理request/response內容。
### 9.1.3 The deployment pipeline
每個service都有deployment pipeline,各步驟理想上是automated,但還是有些步驟是manual的。
deployment pipeline通常使用Continuous Integration (CI) server(Ex. Jenkins):

* Pre-commit tests stage:
Runs the unit tests. This is executed by the developer before committing their changes.
* Commit tests stage:
Compiles the service, runs the unit tests, and performs static code analysis.
* Integration tests stage:
Runs the integration tests.
* Component tests stage:
Runs the component tests for the service.
* Deploy stage:
Deploys the service into production.
## 9.2 Writing unit tests for a service
試想你要測試order service中算錢的功能,可能需要將實際order訂單流程全走一次,到最後才能驗證算錢的功能,這是相當沒效率的。
-> unit test

* Solitary unit test:
Tests a class in isolation using mock objects for the class’s dependencies
* Sociable unit test:
Tests a class and its dependencies
Controller and service classes通常使用solitary unit tests.
Domain objects(entities and value objects) 則通常使用sociable unit tests.

* Entities, such as Order, which as described in chapter 5 are objects with persistent identity, are tested using sociable unit tests.
* Value objects, such as Money, which as described in chapter 5 are objects that are collections of values, are tested using sociable unit tests.
* Sagas, such as CreateOrderSaga, which as described in chapter 4 maintain data consistency across services, are tested using sociable unit tests.
* Domain services, such as OrderService, which as described in chapter 5 are classes that implement business logic that doesn’t belong in entities or value objects, are tested using solitary unit tests.
* Controllers, such as OrderController, which handle HTTP requests, are tested using solitary unit tests.
* Inbound and outbound messaging gateways are tested using solitary unit tests.
### 9.2.1 Developing unit tests for entities
以OrderTest class舉例:

* @Before: create order
* @Test: 初始化並測試order
entities屬於sociable unit tests,而Order class relies on the Money value object
### 9.2.2 Writing unit tests for value objects
Value objects是不變的(immutable),相當容易測試,不需擔心side effects:

### 9.2.3 Developing unit tests for sagas
測試saga時,除了happy path以外,更要測試各種失敗情境。且必須使用real database與message broker模擬saga participants:


### 9.2.4 Writing unit tests for domain services
domain service class(Ex. OrderService),主要功能為調用entities與repositories,並發佈domain events。通常使用solitary unit test,步驟如下:
1. Setup—Configures the mock objects for the service’s dependencies
2. Execute—Invokes a service method
3. Verify—Verifies that the value returned by the service method is correct and that the dependencies have been invoked correctly


### 9.2.5 Developing unit tests for controllers
service可能會依賴來處理HTTP requests(from other services、API gateway)。controller classs內有一系列request handler methods:
> 書中採用Rest Assured Mock MVC來模擬controller classs的dependencies


### 9.2.6 Writing unit tests for event and message handlers
message handler跟controller很像,負責處理domain events publish,但message handler聚焦於服務間的訊息傳遞:

### Summary
* Automated testing
* system under test (SUT):被測試的對象
* 金字塔(pyramid)方式區分測試大小、粗細度...
* test doubles(stubs and mocks)
* stubs:
returns values to the SUT
* mocks:
a test uses to verify that the SUT
* unit測試
* Solitary: domain logic、controller、message adapter
* Sociable: entity、value object、Saga