Architect's Log

I'm a Cloud Architect. I'm highly motivated to reduce toils with driving DevOps.

LINQPadでユニットテストを書くには?

サマリー

LINQPadはv.6.9からxUnitをサポートしていて、ユニットテストが書けます。

https://www.linqpad.net/LINQPad6.aspx

You can now add xunit test support to your query via new option on the Query menu. This adds the required references, a runner, and a sample test method to get you started. There's also a option on the Query menu Alt+Shift+T to execute all tests.

この記事では、LINQPadでのユニットテストの書き方を説明します。

実行環境

LINQPad 7 (Premium Edition) v7.1.5 (X64) on Windows 10

セットアップ

新規でQueryを作成します。LanguageC# Programを選びました。

void Main() {
    
}

// You can define other methods, fields, classes and namespaces here

QueryメニューからAdd XUnit Test Supportを選ぶと、テンプレートが挿入されます。

#load "xunit"

void Main() {
    //RunTests();  // Call RunTests() or press Alt+Shift+T to initiate testing.
}

// You can define other methods, fields, classes and namespaces here

#region private::Tests

[Fact] void Test_Xunit() => Assert.True (1 + 1 == 2);

#endregion

初回はConfirmationダイアログが表示されるので、はいを選んで、xUnitのPackageをダウンロードします。

f:id:JHashimoto:20211226135655p:plain

Alt + Shift + Tでテストを実行できます。

f:id:JHashimoto:20211226135719p:plain

コードを修正して、NGをテストします。

#region private::Tests

[Fact] void Test_Xunit() => Assert.True (1 + 1 == 1);

#endregion

期待通りNGになりました。

f:id:JHashimoto:20211226135742p:plain

コードをテストしてみる

文字列を返す簡単なメソッドとテストコードを書きます。

private string GetGreeting(string name) {
    return $"Hello {name}";
}

#region private::Tests

[Fact] void Test_Xunit() => Assert.True (1 + 1 == 2);

[Fact] void Test_GetGreeting_OK() => Assert.Equal("Hello Bob", GetGreeting("Bob"));
[Fact] void Test_GetGreeting_NG() => Assert.NotEqual("Hello Bob", GetGreeting("Alice"));

#endregion

期待通りのテスト結果になりました。

f:id:JHashimoto:20211226135832p:plain

テストコードを別ファイルにする

コード量が多くなると、テストコードを別ファイルにした方が見通しがよくなります。

Is it possible to use xUnit with LINQPad? - Stack Overflow

This will add a query with required boilerplate code referenced via #load so you can start testing facts and theories instantly.

#loadディレクティブでできるようなので、試してみます。

GetGreetingメソッドをGetGreeting.linqに移動しました。

void Main() {
    //RunTests();  // Call RunTests() or press Alt+Shift+T to initiate testing.
    GetGreeting("Bob").Dump();
}

// You can define other methods, fields, classes and namespaces here

private string GetGreeting(string name) {
    return $"Hello {name}";
}

テストコードに#load "GetGreeting"を入れます。

#load "xunit"
#load "GetGreeting"

#region private::Tests

[Fact] void Test_Xunit() => Assert.True (1 + 1 == 2);

[Fact] void Test_GetGreeting_OK() => Assert.Equal("Hello Bob", GetGreeting("Bob"));
[Fact] void Test_GetGreeting_NG() => Assert.NotEqual("Hello Bob", GetGreeting("Alice"));

#endregion

別ファイルのメソッドをテストできました。

f:id:JHashimoto:20211226135905p:plain

まとめ

LINQPadはVisual Studioに比べてコードを書くまでのオーバーヘッドが小さく、検証・テスト用途で便利に使っていました。一方でテストが書けないためコード量が多くなるにつれ、開発効率が落ちる傾向がありました。

ユニットテストを用意することで、今後は複雑なコードもLINQPadで書けそうな感触を得ました。

参考

forum.linqpad.net