Slide 1

Slide 1 text

Unity 用MockClient のお話 2018/06/19 Jikai Lightning Talks #1

Slide 2

Slide 2 text

imo です

Slide 3

Slide 3 text

最近やったこと テスト導入したりしていました。 https://speakerdeck.com/adarapata/unitypurodakut onitesutowodao-ru-siteikumade?slide=1

Slide 4

Slide 4 text

最近困っていたこと ユニットテストは導入できたが書けないパター ン がある 通信とか挟まるとダメ 通信の結果ごにょごにょとかよくある 通信テスト自体はエディタ拡張している つらい

Slide 5

Slide 5 text

どう解決するか? ユニットテスト時のみモックしてくれる仕組みが 欲しい Unity にそういう機能はないっぽい 通信をモックするクライアントを実装しよう

Slide 6

Slide 6 text

API Client の流れ APIClient にRequestBase を投げると通信してくれる var client = new ApiClient(); client.StartRequest(new FooRequest()); // => Result

Slide 7

Slide 7 text

抽象化してみる IHTTPClient を差し替えれればスマー トっぽい でも結構根っこから変えるのは大変そう IApiClient <=> IRequest 間をごまかそう

Slide 8

Slide 8 text

どうモックするか Moq を利用する https://github.com/moq/moq4 C# 用のモックライブラリ Zenject にOption として付属している .NET 3.5 用と4.6 用どちらも用意してて便利

Slide 9

Slide 9 text

できあがり テスト用に ApiClientMock クラスを作成。 Mock メソッドでモックできる var mock = new ApiClientMock(); var mockResponse = new TResponse(); mock.Mock().Success(mockResponse); mock.StartRequest(new TRequest()); // => Result

Slide 10

Slide 10 text

通信が成功したことにする var mock = new ApiClientMock(); var response = new FooResponse(); mock.Mock().Success(response); var result = mock.StartRequest(new FooRequest()); result.Response.Content; // => FooResponse

Slide 11

Slide 11 text

サー バからエラー が返ってきたことにする var mock = new ApiClientMock(); ErrorResponse error = new ErrorResponse(); mock.Mock().Failure(error); var result = mock.StartRequest(new FooRequest()); result.Response.ErrorResponse; // => ErrorResponse

Slide 12

Slide 12 text

通信エラー が発生したことにする var mock = new ApiClientMock(); mock.Mock().Error(Error.Network); var result = mock.StartRequest(new FooRequest()); result.ErrorCause; // => Error.Network

Slide 13

Slide 13 text

バリデー ション モックしてない部分の通信が走ると落ちる => FooRequest はモックされていません。 ex. client.Mock().Success(res); モックしたレスポンスが適切でなかったら落ちる => レスポンスが間違ってます Expected: But was: モックしたけど呼ばれなかったら落ちる => FooRequest をモックしましたが呼ばれていません!

Slide 14

Slide 14 text

用途 通信の結果で処理が変わるFooUseCase を想定 public class FooUseCase { private IApiClient client; public FooUseCase(IApiClient client) { this.client = client; } public string Run() { var result = client.StartRequest(new FooRequset()); if(result.IsSuccess) { return result.Response.Content.Foo; } else { return "NG"; } } }

Slide 15

Slide 15 text

テストコー ド public class FooUseCaseTest { private IApiClient client; [Test] public void Run_Success() { client = new ApiClientMock(); var response = new FooResponse { Foo = "OK" }; client.Mock() .Success(response); var useCase = new FooUseCase(client); Assert.AreEqual("OK", useCase.Run()); } } ApiClientMock を外から流し込めば意図した挙動にな る

Slide 16

Slide 16 text

Moq 便利 通信部分を気にせずテストが書ける 「 これテスト書けますよ!」 というアプロー チが しやすくなった モックのやり過ぎに注意 テストしないといけない部分をモックしては本末 転倒 何故モックするのかを考える 通信そのものは別でテストしましょう