はじめに
F#を使ってユニットテストしたいですよね。
.NETでmockと言えばMoqですよね。
Moqを使ってユニットテストを試してみましょう。
前提
テスト用のプロジェクト作成からやっていきます。
dotnetのコマンドをぽちぽち打ちながらやっていきます。
下準備
ソリューション作成
今回はNUnitMoq
というソリューションを作ります。
その下にテスト対象のプロジェクトとテストプロジェクトを作っていきます。
mkdir NUnitMoq
cd NUnitMoq
# ソリューション作成
dotnet new sln
プロジェクト作成
テスト対象のプロジェクトとテストプロジェクトを作ります。
# テスト対象のプロジェクト作成
dotnet new console -lang="F#" -o="Sample"
# テストプロジェクトを作成
dotnet new nunit -lang="F#" -o="SampleTest"
それぞれのプロジェクトをソリューションに紐付けます。
dotnet sln NUnitMoq.sln add Sample
dotnet sln NUnitMoq.sln add SampleTest
テストプロジェクトからテスト対象プロジェクトへの参照を追加します。
dotnet add SampleTest reference Sample
FsUnitとMoqの依存を追加
SampleTest配下でこれをする。
dotnet add package FsUnit --version 5.2.0
dotnet add package Moq --version 4.18.4
テスト対象
module TestTarget
open System
open GetDataPort
let getDataWithUpperLetter (getData: GetData) (dataType: DataType) =
getData dataType |> String.map Char.ToUpper
module GetDataPort
type DataType = TypeA | TypeB
type GetData = DataType -> string
module GetData
open GetDataPort
let getData (x: DataType) =
match x with
| TypeA -> "hoge"
| TypeB -> "piyo"
テスト対象になるのはTestTarget.fs
のgetDataWithUpperLetter
です。
GetDataPort
のGetData
を引数として受け取っています。
今回のテストでは、GetDataをmockしていきます。
※GetDataのイメージが付きやすくなるように、GetData.fs
のソースものっけましたが、今回のテストをするだけならGetData.fs
は不要です
テストを書いてみる
open System
open NUnit.Framework
open FsUnit
open Moq
open TestTarget
open GetDataPort
[<TestFixture>]
module GetDataWithUpperLetterTest =
[<Test>]
let ``Moqを使ってテストするぞ``() =
// モックの作成
let getDataMock = new Mock<GetData>()
// モックのセットアップ
getDataMock.Setup(fun x -> x DataType.TypeA).Returns "Hello World"
// モックのオブジェクトを取得
let getData = getDataMock.Object
// テスト実行
getDataWithUpperLetter getData DataType.TypeA |> should equal "HELLO WORLD"
// モックが期待通り動いたか確認
getDataMock.VerifyAll()
SampleTest配下でdotnet test
を打つとテストが実行されます。
VerifyAll()
はセットアップしたモックが正しく呼ばれているかなどを確認できる。
感想
一部C#っぽ記法が出ちゃうのは残念ですが、mockのパッケージを使えるのはありがたい。
色々端折ったところが多いので、ソース見たい方は下記を参照してください。
追記
モックが呼ばれていないことはVerifyNoOtherCalls
で確認できそう
open System
open NUnit.Framework
open FsUnit
open Moq
open TestTarget
open GetDataPort
[<TestFixture>]
module GetDataWithUpperLetterTest =
[<Test>]
let ``Moqを使ってテストするぞ``() =
// モックの作成
let getDataMock = new Mock<GetData>()
// モックのセットアップ
getDataMock.Setup(fun x -> x DataType.TypeA).Returns "Hello World"
// モックのオブジェクトを取得
let getData = getDataMock.Object
// 呼ばれない予定のモック
let notCallMock = new Mock<NotCall>()
let notCall = notCallMock.Object
// テスト実行
getDataWithUpperLetter getData DataType.TypeA notCall |> should equal "HELLO WORLD"
// モックが期待通り動いたか確認
getDataMock.VerifyAll()
// モックが呼ばれていないことの確認
notCallMock.VerifyNoOtherCalls()