---
# System prepended metadata

title: 'Testing microservices: Part 1'
tags: [' Microservice', Microservice Pattern]

---

---
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.

![](https://i.imgur.com/lUtAUnh.jpg)

#### WRITING AUTOMATED TESTS
Automated tests通常透過testing framework開發(ex. JUnit -> Java testing framework)。

automated test由四個步驟組成:
* Setup:
	初始化test fixture(包含SUT及其他會用到部分)
* Execute:
	調用(測試)SUT
* Verify:
	由調用結果驗證SUT
* Teardown:
	清除fixture中測試資料

![](https://i.imgur.com/N0pKi80.jpg)

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

test double:
![](https://i.imgur.com/e8D8MAs.jpg)

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):

![](https://i.imgur.com/xkDtDea.jpg)

*  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):

越下層的測試越簡單、快速，可大量測試，反之，越上層的測試越複雜、慢，無法大量測試。

![](https://i.imgur.com/aepOqe1.jpg)

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

![](https://i.imgur.com/SKPcCpF.jpg)

> * 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

![](https://i.imgur.com/wV0XP6S.jpg)

實務上常用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)

測試流程如下:
![](https://i.imgur.com/q3Wbvw9.jpg)

contract範例:
![](https://i.imgur.com/wQpuJXo.jpg)

#### 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):

![](https://i.imgur.com/uUSSFVR.jpg)

* 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

![](https://i.imgur.com/AU96ORx.jpg)

*  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.

![](https://i.imgur.com/7Qu6HS1.jpg)

* 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舉例:

![](https://imgur.com/IOHKdrJ.jpg)

* @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:

![](https://i.imgur.com/at6jbd4.jpg)

### 9.2.3 Developing unit tests for sagas
測試saga時，除了happy path以外，更要測試各種失敗情境。且必須使用real database與message broker模擬saga participants:
![](https://i.imgur.com/CG4M617.jpg)
![](https://i.imgur.com/TjW1L9o.jpg)

### 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

![](https://i.imgur.com/9A9MJbK.jpg)
![](https://i.imgur.com/TumVZg6.jpg)

### 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

![](https://i.imgur.com/3kw7ARG.jpg)
![](https://i.imgur.com/a7DyG1Z.jpg)

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

![](https://i.imgur.com/LW2lZm7.jpg)

### 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



