SlideShare a Scribd company logo
1 of 51
継続的にテスト可能な設計を考える
ContinuousTestable Design
Atsushi Nakamura
2018.10.12 時点で概ね固まった範囲を一旦公開します
セッション選択の一助にご利用ください
テスト書いてますか?
Copyright 2017 @nuits_jp Slide 3
テストを維持し続けるのは難しい!
Copyright 2017 @nuits_jp Slide 4
ContinuousTestable Design
Today’s Goal
Today’s Goal
Slide 6Copyright 2017 @nuits_jp
継続的にテスト可能な設計を実現するには多くのエッセンスが必要です。
今日はそのうち、つぎの3つについてお話します。
1. 制御の流れと依存方向の分離
2. 依存方向の制御と、安定性と柔軟性の管理
3. 現実的なテスト戦略を考える(結論はこの場ではでない)
「継続的なテストの維持」に必要な一部のエッセンスですが、非常に重要なことです。
ContinuousTestable Design
Overview
1. テスト不可のアプリからスタート
2. リファクタリングしつつ、継続的にテスト可能な設計を目指す
3. テストの対象は「今回は」クラス単位を想定
Overview
• 対象システムは次のような特徴をもちます
• プロダクト別の総売上をCSV出力するコンソール アプリを想定
• 同一のデータベースを他の機能からも利用している
Overview
Copyright 2017 @nuits_jp Slide 9
SQL Server 2017
AdventureWorks2017
Other Functions
※英語含む、対象コードへのマサカリは「そっと」
Pull Requestを投げるというソフト対応をお願いします
https://github.com/nuitsjp/Continuous-Testable-Design
ContinuousTestable Design
プロダクト別 総売上 出力システム
まずはコードを見てみよう
Copyright 2017 @nuits_jp Slide 11
現在の構造
現在の構造
クラス間が直接依存しており
上流のクラスの単体テストができない
ControllerとBusinessLogicの関係
現在、ControllerとBusinessLogicの間には二つの依存関係がある
•BusinessLogicの生成
•BusinessLogicの利用
Controllerをテスト ダブル(Mock・Stub・Fakeなど)を利用してテストできるよ
うにリファクタリングする。
Copyright 2017 @nuits_jp Slide 14
インターフェースの抽出
Copyright 2017 @nuits_jp Slide 15
インターフェースの抽出結果
Copyright 2017 @nuits_jp Slide 16
○ 利用箇所はインターフェース依存になった
× 生成箇所に実装クラス依存が残っている
No. 方式 代表的なデザインパターン
1 Controllerが能動的に取得する Service Locator パターン
2 Controllerに外部から注入する Dependency Injection パターン
インスタンス生成を取り除く二つの方式
Copyright 2017 @nuits_jp Slide 17
基本的にいずれかに類似した方式をとります。
ここではDependency Injectionパターンを利用します。
Service Locator is an Anti-Pattern by Mark Seemann
http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/
• Service Locatorはstaticなレジストリなので並行テストが困難
• ControllerからBusinessLogicへ依存がなくなる代わりに、Service Locatorへ依存が増える
Business Logicをインジェクションする
Copyright 2017 @nuits_jp Slide 18
Dependency Injectionの適用結果
Copyright 2017 @nuits_jp Slide 19
var controller =
new Controller(
new BusinessLogic());
controller.Execute("output.csv");
テスト ダブルの利用
Copyright 2017 @nuits_jp Slide 20
var controller =
new Controller(
newTestDouble());
controller.Execute("output.csv");
さあ、すべてテスタブルに修正しましょう!
Copyright 2017 @nuits_jp Slide 21
しました!
Copyright 2017 @nuits_jp Slide 22
結果、こんな感じでテストできます
Copyright 2017 @nuits_jp Slide 23
単体テスト用DB
class Testable Models
Repositoryの単体テスト
BusinessLogicの単体テスト
Controllerの単体テスト
Controller «interface»
IBusinessLogic
BusinessLogic «interface»
IRepository
Repository
ControllerFixture
BusinessLogicMock
BusinessLogicFixture
RepositoryFixture
RepositoryMock
ところで、よく見ると
Copyright 2017 @nuits_jp Slide 24
なんか嫌な臭いがするぞ?
Copyright 2017 @nuits_jp Slide 25
特にこのあたりが...
Copyright 2017 @nuits_jp Slide 26
ここの向き
良く見てみよう
ControllerがViewに、依存している
一般的にViewは最も変化が多い
⇒ ControllerはViewに引きずられ変更過多になる
⇒ 結果、Controllerのテストコードもテストダブルも変更過多になる
⇒つらい
Copyright 2017 @nuits_jp Slide 27
もうひとつ
Copyright 2017 @nuits_jp Slide 28
ここもちょっとな...
Copyright 2017 @nuits_jp Slide 29
ここの向き
• 同一のデータベースを他の機能からも利用している
• データベースは他システム起因で変更が入る
• そもそもデータが安定的だというのは過去の神話で
ビジネスの変遷の早い現在は、データも安定的ではなくなっている
あらためて全体像を確認する
Copyright 2017 @nuits_jp Slide 30
SQL Server 2017
AdventureWorks2017
Other Functions
class Testable Models
Repositoryの単体テスト
BusinessLogicの単体テスト
Controllerの単体テスト
Controller «interface»
IBusinessLogic
BusinessLogic «interface»
IRepository
Repository
ControllerFixture
BusinessLogicMock
BusinessLogicFixture
RepositoryFixture
RepositoryMock
つまり参照してるテーブルが変更されると…
Copyright 2017 @nuits_jp Slide 31
単体テスト用DB
Breaking
Change!
Breaking
Change!
Breaking
Change!
Breaking
Change!
Breaking
Change!
Breaking
Change!
Breaking
Change!
Breaking
Change!
Breaking
Change!
Breaking
Change!
Breaking
Change!
最悪だ!!
Copyright 2017 @nuits_jp Slide 32
何が悪いのか?
Copyright 2017 @nuits_jp Slide 33
class BusinessLogic and Repository
BusinessLogics Repositories
BusinessLogic «interface»
IRepository
Repository
制御の流れに
引きずられて
安定させたい
モジュール
不安定な
モジュール
依存して
しまっている
解決策
Copyright 2017 @nuits_jp Slide 34
class BusinessLogic and Repository
BusinessLogics Repositories
BusinessLogic «interface»
IRepository
Repository
制御の流れから
依存方向を分離し
逆方向へ依存させる
できます!
Copyright 2017 @nuits_jp Slide 35
こうする!
重要なのは、インターフェースの移動ではなく
IRepositoryをBusinessLogicの文脈で定義すること
Copyright 2017 @nuits_jp Slide 36
class BusinessLogic and Repository
BusinessLogics Repositories
BusinessLogic «interface»
IRepository
Repository
class BusinessLogic and Repository
BusinessLogics Repositories
BusinessLogic «interface»
IRepository
Repository
Before
After
IRepositoryの詳細を見てみましょう
Copyright 2017 @nuits_jp Slide 37
IRepositoryのクラス図とER図
Copyright 2017 @nuits_jp Slide 38
class Repository Details
«interface»
IRepository
+ GetProducts(): IEnumerable<Product>
+ GetSalesOrderDetail(): IEnumerable<SalesOrderDetail>
SalesOrderDetail
«property»
+ CarrierTrackingNumber(): string
+ LineTotal(): decimal
+ ModifiedDate(): DateTime
+ OrderQty(): short
+ ProductID(): int
+ rowguid(): Guid
+ SalesOrderDetailID(): int
+ SalesOrderID(): int
+ SpecialOfferID(): int
+ UnitPrice(): decimal
+ UnitPriceDiscount(): decimal
Product
«property»
+ Class(): string
+ Color(): string
+ DaysToManufacture(): int
+ DiscontinuedDate(): DateTime?
+ FinishedGoodsFlag(): bool
+ ListPrice(): decimal
+ MakeFlag(): bool
+ ModifiedDate(): DateTime
+ Name(): string
+ ProductID(): int
+ ProductLine(): string
+ ProductModelID(): int?
+ ProductNumber(): string
+ ProductSubcategoryID(): int?
+ ReorderPoint(): short
+ rowguid(): Guid
+ SafetyStockLevel(): short
+ SellEndDate(): DateTime?
+ SellStartDate(): DateTime
+ Size(): string
+ SizeUnitMeasureCode(): string
+ StandardCost(): decimal
+ Style(): string
+ Weight(): decimal?
+ WeightUnitMeasureCode(): string
dm SalesOrderDetail and Product
Product
«column»
*PK ProductID: int
* Name: nvarchar(50)
* ProductNumber: nvarchar(25)
* MakeFlag: bit = 1
* FinishedGoodsFlag: bit = 1
Color: nvarchar(15)
* SafetyStockLevel: smallint
* ReorderPoint: smallint
* StandardCost: money
* ListPrice: money
Size: nvarchar(5)
FK SizeUnitMeasureCode: nchar(3)
FK WeightUnitMeasureCode: nchar(3)
Weight: decimal(8,2)
* DaysToManufacture: int
ProductLine: nchar(2)
Class: nchar(2)
Style: nchar(2)
FK ProductSubcategoryID: int
FK ProductModelID: int
* SellStartDate: datetime
SellEndDate: datetime
DiscontinuedDate: datetime
* rowguid: uniqueidentifier = newid()
* ModifiedDate: datetime = getdate()
SalesOrderDetail
«column»
*pfK SalesOrderID: int
*PK SalesOrderDetailID: int
CarrierTrackingNumber: nvarchar(25)
* OrderQty: smallint
*FK ProductID: int
*FK SpecialOfferID: int
* UnitPrice: money
* UnitPriceDiscount: money = 0.0
* LineTotal: numeric(38,6)
* rowguid: uniqueidentifier = newid()
* ModifiedDate: datetime = getdate()
クラス図 ER図
IRepositoryが完全にデータベースの文脈で記述されているのが見て取れる
BusinessLogicのインターフェースと比較する
Copyright 2017 @nuits_jp Slide 39
dm BusinessLogic
«interface»
IBusinessLogic
+ GetProductSalesList(): IEnumerable<ProductSales>
ProductSales
«property»
+ Name(): string
+ Sales(): decimal
プロダクト別の総売上額が欲しいだけ
class Repository Details
«interface»
IRepository
+ GetProducts(): IEnumerable<Product>
+ GetSalesOrderDetail(): IEnumerable<SalesOrderDetail>
SalesOrderDetail
«property»
+ CarrierTrackingNumber(): string
+ LineTotal(): decimal
+ ModifiedDate(): DateTime
+ OrderQty(): short
+ ProductID(): int
+ rowguid(): Guid
+ SalesOrderDetailID(): int
+ SalesOrderID(): int
+ SpecialOfferID(): int
+ UnitPrice(): decimal
+ UnitPriceDiscount(): decimal
Product
«property»
+ Class(): string
+ Color(): string
+ DaysToManufacture(): int
+ DiscontinuedDate(): DateTime?
+ FinishedGoodsFlag(): bool
+ ListPrice(): decimal
+ MakeFlag(): bool
+ ModifiedDate(): DateTime
+ Name(): string
+ ProductID(): int
+ ProductLine(): string
+ ProductModelID(): int?
+ ProductNumber(): string
+ ProductSubcategoryID(): int?
+ ReorderPoint(): short
+ rowguid(): Guid
+ SafetyStockLevel(): short
+ SellEndDate(): DateTime?
+ SellStartDate(): DateTime
+ Size(): string
+ SizeUnitMeasureCode(): string
+ StandardCost(): decimal
+ Style(): string
+ Weight(): decimal?
+ WeightUnitMeasureCode(): string
IRepositoryをBusinessLogicの文脈へリファクタリング
Copyright 2017 @nuits_jp Slide 40
リファクタリング後のIRepository
Copyright 2017 @nuits_jp Slide 41
dm Repositories
ProductName
«property»
+ Name(): string
+ ProductId(): int?
SalesLineTotal
«property»
+ LineTotal(): double
+ ProductId(): int
«interface»
IRepository
+ GetProductNames(): IEnumerable<ProductName>
+ GetSalesLineTotal(): IEnumerable<SalesLineTotal>
一旦整理しましょう
Copyright 2017 @nuits_jp Slide 42
「制御の流れ」と「依存方向」は、つぎの二つによりコントロール可能
• クラスとクラスは直接依存させず、インターフェース(抽象)に依
存させる(依存性逆転の原則)
• インターフェースを適切な文脈で定義する
「制御の流れ」と「依存方向」
Copyright 2017 @nuits_jp Slide 43
class BusinessLogics and Re...
Repositories
BusinessLogics
BusinessLogic
«interface»
IRepository
Repository
依存方向によって決まる、安定性と柔軟性
Copyright 2017 @nuits_jp Slide 44
Repository変更の影響を受けない ⇒ 安定性が高い
変更がRepositoryへ影響を与える ⇒ 柔軟性が低い
BusinessLogic変更の影響を受ける ⇒ 安定性が低い
変更がBusinessLogicへ影響を与えない ⇒ 柔軟性が高い
安定性と柔軟性は設計上トレードオフにある
あらためて全体を見てみる
Copyright 2017 @nuits_jp Slide 45
元々の安定度と柔軟性
Copyright 2017 @nuits_jp Slide 46
凡例
制御の流れ
依存関係
安定性③
柔軟性①
安定性①
柔軟性②
安定性②
柔軟性②
安定性①
柔軟性③
安定性と柔軟性 パッケージ
安定度:高 BusinessLogic
中間 Controller
柔軟性:高 View, Repository
安定性と柔軟性をコントロールする
Copyright 2017 @nuits_jp Slide 47
安定度と柔軟性をコントロールする
Copyright 2017 @nuits_jp Slide 48
凡例
制御の流れ
依存関係
安定性②
柔軟性②
安定性③
柔軟性①
安定性①
柔軟性③
安定性②
柔軟性①
継続的にテスト可能になった(はず)のクラス図
すべてのクラスを同じレベルでテストしますか?
Copyright 2017 @nuits_jp Slide 50
To be continued
ContinuousTestable Design

More Related Content

What's hot

Desktop app dev strategy for .net core 3.0
Desktop app dev strategy for .net core 3.0Desktop app dev strategy for .net core 3.0
Desktop app dev strategy for .net core 3.0Atsushi Nakamura
 
Test automation strategy for .net core 3 transition
Test automation strategy for .net core 3 transitionTest automation strategy for .net core 3 transition
Test automation strategy for .net core 3 transitionTatsuya Ishikawa
 
6万行の TypeScript 移行とその後
6万行の TypeScript 移行とその後6万行の TypeScript 移行とその後
6万行の TypeScript 移行とその後Shingo Sasaki
 
Settings SyncとCodespaceで体験する新世代へのパラダイムシフト
Settings SyncとCodespaceで体験する新世代へのパラダイムシフトSettings SyncとCodespaceで体験する新世代へのパラダイムシフト
Settings SyncとCodespaceで体験する新世代へのパラダイムシフトAtsushi Nakamura
 
Azureクラウドのネイティブアプリ、IoTとエッジAIの管理ソリューション
Azureクラウドのネイティブアプリ、IoTとエッジAIの管理ソリューションAzureクラウドのネイティブアプリ、IoTとエッジAIの管理ソリューション
Azureクラウドのネイティブアプリ、IoTとエッジAIの管理ソリューションJingun Jung
 
『アプリケーション アーキテクチャ ガイド2.0』のガイド
『アプリケーション アーキテクチャ ガイド2.0』のガイド『アプリケーション アーキテクチャ ガイド2.0』のガイド
『アプリケーション アーキテクチャ ガイド2.0』のガイドKentaro Inomata
 
IoT業界で必須サービスになってきたAzure Web PubSubとAzure IoT EdgeのEFLOWについてご紹介
IoT業界で必須サービスになってきたAzure Web PubSubとAzure IoT EdgeのEFLOWについてご紹介IoT業界で必須サービスになってきたAzure Web PubSubとAzure IoT EdgeのEFLOWについてご紹介
IoT業界で必須サービスになってきたAzure Web PubSubとAzure IoT EdgeのEFLOWについてご紹介Jingun Jung
 
Vision AI on Azure IoT Edge
Vision AI on Azure IoT EdgeVision AI on Azure IoT Edge
Vision AI on Azure IoT EdgeJingun Jung
 
Visual Studio 2019で始める「WPF on .NET Core 3.0」開発
Visual Studio 2019で始める「WPF on .NET Core 3.0」開発Visual Studio 2019で始める「WPF on .NET Core 3.0」開発
Visual Studio 2019で始める「WPF on .NET Core 3.0」開発Atsushi Nakamura
 
DDD Alliance レガシーなコードにドメイン駆動設計で立ち向かった5年間の軌跡
DDD Alliance レガシーなコードにドメイン駆動設計で立ち向かった5年間の軌跡DDD Alliance レガシーなコードにドメイン駆動設計で立ち向かった5年間の軌跡
DDD Alliance レガシーなコードにドメイン駆動設計で立ち向かった5年間の軌跡BIGLOBE Inc.
 
Adobe XD Plugin「Scenegraph」の操作とDialogの作り方
Adobe XD Plugin「Scenegraph」の操作とDialogの作り方Adobe XD Plugin「Scenegraph」の操作とDialogの作り方
Adobe XD Plugin「Scenegraph」の操作とDialogの作り方Yoshiki Takeoka
 
【de:code 2020】 Build 2020 最新情報 〜 Azure & Visual Studio & .NET 〜
【de:code 2020】 Build 2020 最新情報 〜 Azure & Visual Studio & .NET 〜【de:code 2020】 Build 2020 最新情報 〜 Azure & Visual Studio & .NET 〜
【de:code 2020】 Build 2020 最新情報 〜 Azure & Visual Studio & .NET 〜日本マイクロソフト株式会社
 
WeDX Flow Hands-on
WeDX Flow Hands-onWeDX Flow Hands-on
WeDX Flow Hands-onJingun Jung
 
SIerで幸せな技術キャリアを築くために
SIerで幸せな技術キャリアを築くためにSIerで幸せな技術キャリアを築くために
SIerで幸せな技術キャリアを築くためにTakanari Konishi
 
30分でできる!Adobe XDプラグイン開発!
30分でできる!Adobe XDプラグイン開発!30分でできる!Adobe XDプラグイン開発!
30分でできる!Adobe XDプラグイン開発!Yoshiki Takeoka
 
言語系サービスの統合ポータル Language Studio で Microsoft AI を再確認
言語系サービスの統合ポータル Language Studio で Microsoft AI を再確認言語系サービスの統合ポータル Language Studio で Microsoft AI を再確認
言語系サービスの統合ポータル Language Studio で Microsoft AI を再確認Yoshitaka Seo
 
Adobe XDプラグインをつくってみよう
Adobe XDプラグインをつくってみようAdobe XDプラグインをつくってみよう
Adobe XDプラグインをつくってみようYoshiki Takeoka
 
DDD sample code explained in Java
DDD sample code explained in JavaDDD sample code explained in Java
DDD sample code explained in Java増田 亨
 

What's hot (20)

Desktop app dev strategy for .net core 3.0
Desktop app dev strategy for .net core 3.0Desktop app dev strategy for .net core 3.0
Desktop app dev strategy for .net core 3.0
 
Test automation strategy for .net core 3 transition
Test automation strategy for .net core 3 transitionTest automation strategy for .net core 3 transition
Test automation strategy for .net core 3 transition
 
デスクトップ向けUIコンポーネントの対応状況と今後の予定
デスクトップ向けUIコンポーネントの対応状況と今後の予定デスクトップ向けUIコンポーネントの対応状況と今後の予定
デスクトップ向けUIコンポーネントの対応状況と今後の予定
 
6万行の TypeScript 移行とその後
6万行の TypeScript 移行とその後6万行の TypeScript 移行とその後
6万行の TypeScript 移行とその後
 
Settings SyncとCodespaceで体験する新世代へのパラダイムシフト
Settings SyncとCodespaceで体験する新世代へのパラダイムシフトSettings SyncとCodespaceで体験する新世代へのパラダイムシフト
Settings SyncとCodespaceで体験する新世代へのパラダイムシフト
 
Azureクラウドのネイティブアプリ、IoTとエッジAIの管理ソリューション
Azureクラウドのネイティブアプリ、IoTとエッジAIの管理ソリューションAzureクラウドのネイティブアプリ、IoTとエッジAIの管理ソリューション
Azureクラウドのネイティブアプリ、IoTとエッジAIの管理ソリューション
 
『アプリケーション アーキテクチャ ガイド2.0』のガイド
『アプリケーション アーキテクチャ ガイド2.0』のガイド『アプリケーション アーキテクチャ ガイド2.0』のガイド
『アプリケーション アーキテクチャ ガイド2.0』のガイド
 
IoT業界で必須サービスになってきたAzure Web PubSubとAzure IoT EdgeのEFLOWについてご紹介
IoT業界で必須サービスになってきたAzure Web PubSubとAzure IoT EdgeのEFLOWについてご紹介IoT業界で必須サービスになってきたAzure Web PubSubとAzure IoT EdgeのEFLOWについてご紹介
IoT業界で必須サービスになってきたAzure Web PubSubとAzure IoT EdgeのEFLOWについてご紹介
 
Vision AI on Azure IoT Edge
Vision AI on Azure IoT EdgeVision AI on Azure IoT Edge
Vision AI on Azure IoT Edge
 
Visual Studio 2019で始める「WPF on .NET Core 3.0」開発
Visual Studio 2019で始める「WPF on .NET Core 3.0」開発Visual Studio 2019で始める「WPF on .NET Core 3.0」開発
Visual Studio 2019で始める「WPF on .NET Core 3.0」開発
 
DDD Alliance レガシーなコードにドメイン駆動設計で立ち向かった5年間の軌跡
DDD Alliance レガシーなコードにドメイン駆動設計で立ち向かった5年間の軌跡DDD Alliance レガシーなコードにドメイン駆動設計で立ち向かった5年間の軌跡
DDD Alliance レガシーなコードにドメイン駆動設計で立ち向かった5年間の軌跡
 
Adobe XD Plugin「Scenegraph」の操作とDialogの作り方
Adobe XD Plugin「Scenegraph」の操作とDialogの作り方Adobe XD Plugin「Scenegraph」の操作とDialogの作り方
Adobe XD Plugin「Scenegraph」の操作とDialogの作り方
 
【de:code 2020】 Build 2020 最新情報 〜 Azure & Visual Studio & .NET 〜
【de:code 2020】 Build 2020 最新情報 〜 Azure & Visual Studio & .NET 〜【de:code 2020】 Build 2020 最新情報 〜 Azure & Visual Studio & .NET 〜
【de:code 2020】 Build 2020 最新情報 〜 Azure & Visual Studio & .NET 〜
 
WeDX Flow Hands-on
WeDX Flow Hands-onWeDX Flow Hands-on
WeDX Flow Hands-on
 
SIerで幸せな技術キャリアを築くために
SIerで幸せな技術キャリアを築くためにSIerで幸せな技術キャリアを築くために
SIerで幸せな技術キャリアを築くために
 
Hacktoberfest 概要、Node-REDプロジェクト貢献手順
Hacktoberfest 概要、Node-REDプロジェクト貢献手順Hacktoberfest 概要、Node-REDプロジェクト貢献手順
Hacktoberfest 概要、Node-REDプロジェクト貢献手順
 
30分でできる!Adobe XDプラグイン開発!
30分でできる!Adobe XDプラグイン開発!30分でできる!Adobe XDプラグイン開発!
30分でできる!Adobe XDプラグイン開発!
 
言語系サービスの統合ポータル Language Studio で Microsoft AI を再確認
言語系サービスの統合ポータル Language Studio で Microsoft AI を再確認言語系サービスの統合ポータル Language Studio で Microsoft AI を再確認
言語系サービスの統合ポータル Language Studio で Microsoft AI を再確認
 
Adobe XDプラグインをつくってみよう
Adobe XDプラグインをつくってみようAdobe XDプラグインをつくってみよう
Adobe XDプラグインをつくってみよう
 
DDD sample code explained in Java
DDD sample code explained in JavaDDD sample code explained in Java
DDD sample code explained in Java
 

Similar to 継続的にテスト可能な設計を考える ベータ版

RxDataSourceをNSDiffableDataSourceへ置き換える際のTips集紹介
RxDataSourceをNSDiffableDataSourceへ置き換える際のTips集紹介RxDataSourceをNSDiffableDataSourceへ置き換える際のTips集紹介
RxDataSourceをNSDiffableDataSourceへ置き換える際のTips集紹介Fumiya Sakai
 
JaSST2017_大規模業務システムにおける再利用可能なテスト自動化の取り組み
JaSST2017_大規模業務システムにおける再利用可能なテスト自動化の取り組みJaSST2017_大規模業務システムにおける再利用可能なテスト自動化の取り組み
JaSST2017_大規模業務システムにおける再利用可能なテスト自動化の取り組みHideki Sugimoto
 
iOSやAndroidアプリ開発のGoodPractice
iOSやAndroidアプリ開発のGoodPracticeiOSやAndroidアプリ開発のGoodPractice
iOSやAndroidアプリ開発のGoodPracticeKen Morishita
 
日立ソリューションズの取り組みとプラットフォーム関連セション内容のご紹介
日立ソリューションズの取り組みとプラットフォーム関連セション内容のご紹介日立ソリューションズの取り組みとプラットフォーム関連セション内容のご紹介
日立ソリューションズの取り組みとプラットフォーム関連セション内容のご紹介CASAREAL, Inc.
 
ASP.NET MVC 2 ~新機能の紹介~
ASP.NET MVC 2 ~新機能の紹介~ASP.NET MVC 2 ~新機能の紹介~
ASP.NET MVC 2 ~新機能の紹介~Yoshitaka Seo
 
CodeIgniter 〜 2008年大躍進のPHPフレームワーク
CodeIgniter 〜 2008年大躍進のPHPフレームワークCodeIgniter 〜 2008年大躍進のPHPフレームワーク
CodeIgniter 〜 2008年大躍進のPHPフレームワークkenjis
 
システムのモダナイズ 落ちても良いアプリの作り方
システムのモダナイズ 落ちても良いアプリの作り方システムのモダナイズ 落ちても良いアプリの作り方
システムのモダナイズ 落ちても良いアプリの作り方Chihiro Ito
 
B13_株式会社資生堂 プロフェッショナル事業の日本とタイの基幹系業務を「 Microsoft Dynamics 365 」で統合管理 [Microsof...
B13_株式会社資生堂 プロフェッショナル事業の日本とタイの基幹系業務を「 Microsoft Dynamics 365 」で統合管理 [Microsof...B13_株式会社資生堂 プロフェッショナル事業の日本とタイの基幹系業務を「 Microsoft Dynamics 365 」で統合管理 [Microsof...
B13_株式会社資生堂 プロフェッショナル事業の日本とタイの基幹系業務を「 Microsoft Dynamics 365 」で統合管理 [Microsof...日本マイクロソフト株式会社
 
DeNA のデータ活用を支える BigQuery データの民主化とガバナンス強化の軌跡 | Google Cloud INSIDE Games & App...
DeNA のデータ活用を支える BigQuery データの民主化とガバナンス強化の軌跡 | Google Cloud INSIDE Games & App...DeNA のデータ活用を支える BigQuery データの民主化とガバナンス強化の軌跡 | Google Cloud INSIDE Games & App...
DeNA のデータ活用を支える BigQuery データの民主化とガバナンス強化の軌跡 | Google Cloud INSIDE Games & App...Google Cloud Platform - Japan
 
Intalio会社概要とbpmsの特長20100319
Intalio会社概要とbpmsの特長20100319Intalio会社概要とbpmsの特長20100319
Intalio会社概要とbpmsの特長20100319Tomoaki Sawada
 
SharePoint Business Connectivity Services を使用した外部アプリケーション連携
SharePoint Business Connectivity Services を使用した外部アプリケーション連携SharePoint Business Connectivity Services を使用した外部アプリケーション連携
SharePoint Business Connectivity Services を使用した外部アプリケーション連携Atsuo Yamasaki
 
Spring Fest 2017 「エンタープライズで利用するSpring Boot」#jsug #sf_h1
Spring Fest 2017 「エンタープライズで利用するSpring Boot」#jsug #sf_h1Spring Fest 2017 「エンタープライズで利用するSpring Boot」#jsug #sf_h1
Spring Fest 2017 「エンタープライズで利用するSpring Boot」#jsug #sf_h1Takeshi Hirosue
 
インタリオカンファレンス案内(修正版)3
インタリオカンファレンス案内(修正版)3インタリオカンファレンス案内(修正版)3
インタリオカンファレンス案内(修正版)3Tomoaki Sawada
 
ADO.NET Entity Framework
ADO.NET Entity Framework ADO.NET Entity Framework
ADO.NET Entity Framework Microsoft
 
そのデータ、活かせていますか?
そのデータ、活かせていますか?そのデータ、活かせていますか?
そのデータ、活かせていますか?Miho Yamamoto
 

Similar to 継続的にテスト可能な設計を考える ベータ版 (20)

お客様が望んでいるモダンデスクトップアプリとは?/傾向と対策 Part1
お客様が望んでいるモダンデスクトップアプリとは?/傾向と対策 Part1お客様が望んでいるモダンデスクトップアプリとは?/傾向と対策 Part1
お客様が望んでいるモダンデスクトップアプリとは?/傾向と対策 Part1
 
RxDataSourceをNSDiffableDataSourceへ置き換える際のTips集紹介
RxDataSourceをNSDiffableDataSourceへ置き換える際のTips集紹介RxDataSourceをNSDiffableDataSourceへ置き換える際のTips集紹介
RxDataSourceをNSDiffableDataSourceへ置き換える際のTips集紹介
 
Ms retail update ra 20191030
Ms retail update ra 20191030Ms retail update ra 20191030
Ms retail update ra 20191030
 
JaSST2017_大規模業務システムにおける再利用可能なテスト自動化の取り組み
JaSST2017_大規模業務システムにおける再利用可能なテスト自動化の取り組みJaSST2017_大規模業務システムにおける再利用可能なテスト自動化の取り組み
JaSST2017_大規模業務システムにおける再利用可能なテスト自動化の取り組み
 
iOSやAndroidアプリ開発のGoodPractice
iOSやAndroidアプリ開発のGoodPracticeiOSやAndroidアプリ開発のGoodPractice
iOSやAndroidアプリ開発のGoodPractice
 
日立ソリューションズの取り組みとプラットフォーム関連セション内容のご紹介
日立ソリューションズの取り組みとプラットフォーム関連セション内容のご紹介日立ソリューションズの取り組みとプラットフォーム関連セション内容のご紹介
日立ソリューションズの取り組みとプラットフォーム関連セション内容のご紹介
 
[Japan Tech summit 2017] DAL 006
[Japan Tech summit 2017] DAL 006[Japan Tech summit 2017] DAL 006
[Japan Tech summit 2017] DAL 006
 
ASP.NET MVC 2 ~新機能の紹介~
ASP.NET MVC 2 ~新機能の紹介~ASP.NET MVC 2 ~新機能の紹介~
ASP.NET MVC 2 ~新機能の紹介~
 
CodeIgniter 〜 2008年大躍進のPHPフレームワーク
CodeIgniter 〜 2008年大躍進のPHPフレームワークCodeIgniter 〜 2008年大躍進のPHPフレームワーク
CodeIgniter 〜 2008年大躍進のPHPフレームワーク
 
システムのモダナイズ 落ちても良いアプリの作り方
システムのモダナイズ 落ちても良いアプリの作り方システムのモダナイズ 落ちても良いアプリの作り方
システムのモダナイズ 落ちても良いアプリの作り方
 
B13_株式会社資生堂 プロフェッショナル事業の日本とタイの基幹系業務を「 Microsoft Dynamics 365 」で統合管理 [Microsof...
B13_株式会社資生堂 プロフェッショナル事業の日本とタイの基幹系業務を「 Microsoft Dynamics 365 」で統合管理 [Microsof...B13_株式会社資生堂 プロフェッショナル事業の日本とタイの基幹系業務を「 Microsoft Dynamics 365 」で統合管理 [Microsof...
B13_株式会社資生堂 プロフェッショナル事業の日本とタイの基幹系業務を「 Microsoft Dynamics 365 」で統合管理 [Microsof...
 
DeNA のデータ活用を支える BigQuery データの民主化とガバナンス強化の軌跡 | Google Cloud INSIDE Games & App...
DeNA のデータ活用を支える BigQuery データの民主化とガバナンス強化の軌跡 | Google Cloud INSIDE Games & App...DeNA のデータ活用を支える BigQuery データの民主化とガバナンス強化の軌跡 | Google Cloud INSIDE Games & App...
DeNA のデータ活用を支える BigQuery データの民主化とガバナンス強化の軌跡 | Google Cloud INSIDE Games & App...
 
Intalio会社概要とbpmsの特長20100319
Intalio会社概要とbpmsの特長20100319Intalio会社概要とbpmsの特長20100319
Intalio会社概要とbpmsの特長20100319
 
SharePoint Business Connectivity Services を使用した外部アプリケーション連携
SharePoint Business Connectivity Services を使用した外部アプリケーション連携SharePoint Business Connectivity Services を使用した外部アプリケーション連携
SharePoint Business Connectivity Services を使用した外部アプリケーション連携
 
ファーストアカウンティング会社説明資料 for engineer 2022年7月版
ファーストアカウンティング会社説明資料 for engineer 2022年7月版ファーストアカウンティング会社説明資料 for engineer 2022年7月版
ファーストアカウンティング会社説明資料 for engineer 2022年7月版
 
Spring Fest 2017 「エンタープライズで利用するSpring Boot」#jsug #sf_h1
Spring Fest 2017 「エンタープライズで利用するSpring Boot」#jsug #sf_h1Spring Fest 2017 「エンタープライズで利用するSpring Boot」#jsug #sf_h1
Spring Fest 2017 「エンタープライズで利用するSpring Boot」#jsug #sf_h1
 
インタリオカンファレンス案内(修正版)3
インタリオカンファレンス案内(修正版)3インタリオカンファレンス案内(修正版)3
インタリオカンファレンス案内(修正版)3
 
ADO.NET Entity Framework
ADO.NET Entity Framework ADO.NET Entity Framework
ADO.NET Entity Framework
 
そのデータ、活かせていますか?
そのデータ、活かせていますか?そのデータ、活かせていますか?
そのデータ、活かせていますか?
 
【2018年3月時点】Oracle Data Visualizaion ご紹介
【2018年3月時点】Oracle Data Visualizaion ご紹介【2018年3月時点】Oracle Data Visualizaion ご紹介
【2018年3月時点】Oracle Data Visualizaion ご紹介
 

More from Atsushi Nakamura

Unicodeで半角全角を扱うAmbiguous(曖昧さ)とUncertainty(不確実性)の恐怖
Unicodeで半角全角を扱うAmbiguous(曖昧さ)とUncertainty(不確実性)の恐怖Unicodeで半角全角を扱うAmbiguous(曖昧さ)とUncertainty(不確実性)の恐怖
Unicodeで半角全角を扱うAmbiguous(曖昧さ)とUncertainty(不確実性)の恐怖Atsushi Nakamura
 
世界一わかりやすいClean Architecture release-preview
世界一わかりやすいClean Architecture release-preview世界一わかりやすいClean Architecture release-preview
世界一わかりやすいClean Architecture release-previewAtsushi Nakamura
 
App center analyticsを使い倒そう
App center analyticsを使い倒そうApp center analyticsを使い倒そう
App center analyticsを使い倒そうAtsushi Nakamura
 
Old:App center analyticsを使い倒そう
Old:App center analyticsを使い倒そうOld:App center analyticsを使い倒そう
Old:App center analyticsを使い倒そうAtsushi Nakamura
 
Xamarin.forms navigation overview
Xamarin.forms navigation overviewXamarin.forms navigation overview
Xamarin.forms navigation overviewAtsushi Nakamura
 
App center analyticsを使い倒そう
App center analyticsを使い倒そうApp center analyticsを使い倒そう
App center analyticsを使い倒そうAtsushi Nakamura
 
Blue monkey architecture overview
Blue monkey architecture overviewBlue monkey architecture overview
Blue monkey architecture overviewAtsushi Nakamura
 
Xamarin Dev days 2 xamarin.forms ja
Xamarin Dev days 2   xamarin.forms jaXamarin Dev days 2   xamarin.forms ja
Xamarin Dev days 2 xamarin.forms jaAtsushi Nakamura
 
Why prism for xamarin.forms
Why prism for xamarin.formsWhy prism for xamarin.forms
Why prism for xamarin.formsAtsushi Nakamura
 
Enterpriseから見たXamarinの可能性
Enterpriseから見たXamarinの可能性Enterpriseから見たXamarinの可能性
Enterpriseから見たXamarinの可能性Atsushi Nakamura
 

More from Atsushi Nakamura (10)

Unicodeで半角全角を扱うAmbiguous(曖昧さ)とUncertainty(不確実性)の恐怖
Unicodeで半角全角を扱うAmbiguous(曖昧さ)とUncertainty(不確実性)の恐怖Unicodeで半角全角を扱うAmbiguous(曖昧さ)とUncertainty(不確実性)の恐怖
Unicodeで半角全角を扱うAmbiguous(曖昧さ)とUncertainty(不確実性)の恐怖
 
世界一わかりやすいClean Architecture release-preview
世界一わかりやすいClean Architecture release-preview世界一わかりやすいClean Architecture release-preview
世界一わかりやすいClean Architecture release-preview
 
App center analyticsを使い倒そう
App center analyticsを使い倒そうApp center analyticsを使い倒そう
App center analyticsを使い倒そう
 
Old:App center analyticsを使い倒そう
Old:App center analyticsを使い倒そうOld:App center analyticsを使い倒そう
Old:App center analyticsを使い倒そう
 
Xamarin.forms navigation overview
Xamarin.forms navigation overviewXamarin.forms navigation overview
Xamarin.forms navigation overview
 
App center analyticsを使い倒そう
App center analyticsを使い倒そうApp center analyticsを使い倒そう
App center analyticsを使い倒そう
 
Blue monkey architecture overview
Blue monkey architecture overviewBlue monkey architecture overview
Blue monkey architecture overview
 
Xamarin Dev days 2 xamarin.forms ja
Xamarin Dev days 2   xamarin.forms jaXamarin Dev days 2   xamarin.forms ja
Xamarin Dev days 2 xamarin.forms ja
 
Why prism for xamarin.forms
Why prism for xamarin.formsWhy prism for xamarin.forms
Why prism for xamarin.forms
 
Enterpriseから見たXamarinの可能性
Enterpriseから見たXamarinの可能性Enterpriseから見たXamarinの可能性
Enterpriseから見たXamarinの可能性
 

継続的にテスト可能な設計を考える ベータ版

Editor's Notes

  1. みなさんこんにちは。 ご紹介いただきました。ニュイこと中村です。 今日は 継続的にテスト可能な設計を考える というTitleでお話しさせていただこうと思います。 よろしくお願いいたします。
  2. ところで皆さん、日常的に自動テスト書いてますか? 私は結構書いてます。 SIerのテストというと、Excel!スクショ!エビデンス!的なイメージがあるかも知れませんが たまたま巡り合わせが良くて、2000年からJUnitを触っていたと思います。 SIerって、プロダクトチームの維持が難しくて、半年ごとに8割のメンバーが入れ替わってる みたいな地獄みたいな事が良くあるので、自動テストが無いと怖くて生きていけない というのが、私のテストのモチベーションなんだと思います。 ただ、テストを書くのは良いんですが、本当に難しいのはプロダクトの改修に追随して テストを維持していくことだと、私は思っています。
  3. テストを維持し続けるのは本当に難しいです。 プロジェクトのスケジュールが厳しくなると、すぐ悪魔が囁き始めますし テストを維持する事自体が、ソフトウェアの変更を阻害するようなこともあります。 実際に、テストをいくらか破棄して泣く泣く規模を縮小したりしたこともあります。
  4. という訳で、本日のゴールです。
  5. 今日は、そういった茨の道で試行錯誤してきたベストプラクティスの中から 特に大切だと思っている、三つのエッセンスについてお話ししたいと思います。
  6. このセッションの概要ですが
  7. 実際のコードを見ながら、最初はテスト不可能なコードからスタートして リファクタリングしながら、継続的にテスト可能な設計を目指したいと思います。 なお、テストの対象は今回はクラス単位のテストをする前提とさせていただきます。
  8. 実際の例に用いるプログラムですが、SQL ServerのサンプルDBのAdventureWorksを 利用させてもらって、プロダクト別の総売上をCSV出力するような コンソールアプリを想定します。 そのアプリから利用するデータベースは、同一システムの別機能からも利用されるものとします。 コードはこちらのURLに公開しています。 なおコードや、コードの英語に不備不満のある方は、そっとプルリクを送っていただけると助かります。 まえに「その単語、不可算名詞だからsつくのおかしくね?」みたいなマサカリをぶん投げてきた人がいるんですが なるべく、そっとやさしくお願いします。 今日は強そうな人が多いので、重々よろしくお願いいたします。
  9. では早速、本題に入りたいと思います。
  10. まずはコードを見てください。
  11. さて、今見ていただいたコードですが クラス図に落とすと、こんな感じです。 今日のテスト対象はクラスですから
  12. ① さて、今見ていただいたコードですが クラス図に落とすと、こんな感じです。 今日のテスト対象はクラスですから ② この辺のクラス間が直接依存してるせいで 上流のクラスが単体テストできない状態になっています。
  13. 例えばControllerとBusinessLogicの関係の詳細を見てみると その二つの間には、オブジェクトの生成と利用という2種類の依存関係があります。 これらが、Controllerをテストダブルを利用して単体テストすることを阻んでいます。 という訳で、これらのクラス間の直接的な依存関係を取り除いていきます。
  14. まずはインターフェースを抽出します。 ここからは、またコードに戻ります。
  15. さて、こうしたことで、BusinessLogicを利用している箇所の依存関係は クラスからインターフェース移すことができました。 ただし、インスタンスを生成する個所に依存がまだ残っています。
  16. インスタンス生成の依存関係を取り除くには、基本的にはインスタンスの生成を つぎの二つの何れかの方法で解決する必要があります。 一つはControllerが能動的に、インスタンスをいずれかのレジストリーに取得しに行く方法。 もう一つは依存オブジェクトをControllerの外から、誰かに注入してもらう方法です。 それぞれ代表的な実現方法として、ServiceLocatorパターンとDependency Injectionパターンがあります。 今回はDependency Injectionパターン、つまりDIを利用します。 なぜDIを利用するかは、ざっくりいうと、ServiceLocatorには大きな問題が二つあって 一つはテストをマルチスレッドで実装しにくいということと ServiceLocatorパターンにするとBusinessLogicへの依存は減るけど、ServiceLocator への依存が増えて、依存数が減らないという欠点があるためです。
  17. という訳でBusinessLogicをインジェクションするように修正します。
  18. というわけで、無事にControllerからインスタンス生成のロジックも除去出来て 完全にクラス間の依存関係を無くせました。
  19. こうする事で、簡単にBusinessLogicをテストダブルに置き換えが可能になって テスタブルになります。 ちなみにDIパターンとDIコンテナが混同されているケースがありますが DIコンテナはあくまでDIパターンを便利に実現するためのツールなので 必ずしも使わなくてもDIパターンは実現できます。普通は使いますけど。
  20. では他の部分もテスタブルにしましょう!
  21. はいできました!すいません、時間がないので3分間クッキング方式を 取らせていただきます。 Controller、View、BusinessLogic、Repositoryの全てに インターフェースを導出し、DIを適用します。 こうする事で
  22. こんな感じで、全てのクラスにたいしてクラス単位のテストが実施できるようになりました。
  23. ところでこのクラス図
  24. 良く見ると不吉なにおいがしますね?
  25. 特にこの、ControllerとViewの間です。
  26. ①ControllerがViewに依存している部分です。 ②一般的にViewは最も変化が多いと言われていますよね。 それが正しいとすると ③Viewに依存しているControllerはViewに引きずられて 頻繁に変更する必要がでてきます ④結果、プロダクションコードだけでなく、テストコードもテストダブルも 頻繁に変更しなくてはならなくなります ⑤これは辛いです
  27. そしてもう一つ 個人的にはこっちの方が嫌な予感がします。
  28. このBusinessLogicがRepositoryに依存しているところです。
  29. 最初にお話しした通り、このシステムで利用するデータベースは 他の機能からも利用されます。 ということは、このシステムではない、別の機能起因で変更が入る可能性があります。 そもそもデータが安定的であるというのも、私は懐疑的です。 現代において企業は、顧客に対して新しい価値を次々提供し続けなくてはなりません。 新しい価値を提供するためには、往々にして新しいデータが発生します。 データの取り扱いが無くなる事は少なくても、追加変更はそれなりに発生するのが現実だと 私は思っています。
  30. ①つまり、何らかの要因で参照しているテーブルに変更が発生すると ②リポジトリが変更されます ③当然そうなるとテストケースの修正が入って ④高い確率でリポジトリのインターフェースが変更されます ⑤するとビジネスロジックが影響を受けて ⑥リポジトリのモックとビジネスロジックのテストががががが 全部なおさなきゃ!
  31. 最悪だ!と、なってしまうかもしれないです。 実際稀に良くありますし。
  32. つまり何が悪いかというと ①安定させたいビジネスロジックが ②不安定なモジュールにたいして ③制御の流れが原因で引きずられて ④依存してしまっているのが、この問題の根幹にあります これを解決するには
  33. 制御の流れから依存方向を分離して ①逆方向に依存させれば解決できます
  34. もちろん実現可能です
  35. 具体的には、今こうなっているのを ①こうします。重要なのは、インターフェースを移動することではなくて ②リポジトリをビジネスロジックの文脈で定義することです
  36. リポジトリの詳細を見てみましょう
  37. 現在の実装は、リポジトリが完全にデータベースの文脈で記述されているのが見て取れます。
  38. しかし、ビジネスロジックで実現したいのは、プロダクト別の総売上額です。 ①つまりビジネスロジックに必要なのはこの4項目だけです。
  39. という訳で、リポジトリインターフェースを ビジネスロジックの文脈へリファクタリングします
  40. 結果、こうなりました。 データベースの詳細が隠蔽されているのが 分かるかと思います。
  41. 一旦整理しましょう。
  42. 制御の流れと、依存方向は、必ずしも一致させる必要はありません。 クラスとクラスの直接依存を避けて、インターフェースを定義し、疎結合にした上で インターフェースを依存させたい側の文脈で定義することで 依存方向は制御の流れから分離して、自由にコントロールできます。
  43. そして、依存方向によって安定性と柔軟性が変化します。 リポジトリインターフェースは、ビジネスロジックの文脈で記述されています。 ①つまり、データベースの影響を受けにくく、安定性が高くなります。 しかし逆にいうと、ビジネスロジックを変更すると、リポジトリの実装が影響を受ける可能性があるため ビジネスロジックの柔軟性は低くなります。 ②逆にリポジトリの実装はビジネスロジックの変更の影響を受ける為、安定性は低くなります。 しかし、リポジトリの変更はビジネスロジックへ影響を与えにくいため、変更しやすく、柔軟性が高いといえます。 ③つまり、安定性と柔軟性は設計上のトレードオフにあるわけです。
  44. あらためて全体を見てみましょう。
  45. クラスを書くと煩雑なので、パッケージだけ記述しました。 最初の設計では制御の流れと依存関係が一致していたため それぞれのパッケージの安定性と柔軟性は、この図のような 状態にあります。 ビューとリポジトリが一番安定している。つまり変更しに状態にあり それらを修正すると、システム全体への影響が大きい状態に なってしまっています。
  46. 実際には安定性と柔軟性は、だいたいこんな感じにしたいとします。 ビジネスロジックを最も安定させ ビューとレポジトリーは柔軟性を高めたい、つまり変更しやすくしたいとします。
  47. その為にはコントローラーとビュー、ビジネスロジックとリポジトリの間の 依存関係を逆転してあげれば、望む通りの安定性と柔軟性を 得ることができるわけです。
  48. これで変更を受けやすい部分の柔軟性が高くなり、それ以外への影響が およびにくくなりました。 つまり、テストコードへの影響も局所化できて、継続的にテストをしやすい状態に なったはずです。 なったんですが、そこで疑問が発生します。
  49. 全部テストできるからと、すべてのクラスを同じレベルでテストする必要があるんでしょうか?
  50. 以上で私の発表を終わります。 ご清聴ありがとうございました。