csharp-mstest
MSTest 3.x/4.x を使ったユニットテストのベストプラクティスを提供します。モダンなアサーション API の活用方法やデータ駆動テストの実装など、効果的なテスト設計に役立つ知識が得られます。
description の原文を見る
Get best practices for MSTest 3.x/4.x unit testing, including modern assertion APIs and data-driven tests
SKILL.md 本文
MSTest ベストプラクティス (MSTest 3.x/4.x)
モダンな MSTest を使った効果的なユニットテストの作成を支援します。現在の API とベストプラクティスに従います。
プロジェクトセットアップ
- テストプロジェクトは
[ProjectName].Testsという命名規則を使用する - MSTest 3.x 以上の NuGet パッケージを参照する (アナライザーを含む)
- 簡潔なプロジェクトセットアップのために MSTest.Sdk の使用を検討する
dotnet testでテストを実行する
テストクラスの構造
- テストクラスには
[TestClass]属性を使用する - テストクラスはデフォルトで sealed にする パフォーマンスと設計の明確性のため
- テストメソッドには
[TestMethod]を使用する ([DataTestMethod]より推奨) - Arrange-Act-Assert (AAA) パターンに従う
- テストに
MethodName_Scenario_ExpectedBehaviorというパターンで命名する
[TestClass]
public sealed class CalculatorTests
{
[TestMethod]
public void Add_TwoPositiveNumbers_ReturnsSum()
{
// Arrange
var calculator = new Calculator();
// Act
var result = calculator.Add(2, 3);
// Assert
Assert.AreEqual(5, result);
}
}
テストライフサイクル
[TestInitialize]よりコンストラクタを推奨 -readonlyフィールドを有効にし、標準的な C# パターンに従う[TestCleanup]はテストが失敗した場合でも実行する必要があるクリーンアップに使用する- 非同期セットアップが必要な場合は、コンストラクタと非同期
[TestInitialize]を組み合わせる
[TestClass]
public sealed class ServiceTests
{
private readonly MyService _service; // コンストラクタで readonly を有効化
public ServiceTests()
{
_service = new MyService();
}
[TestInitialize]
public async Task InitAsync()
{
// 非同期初期化のみに使用する
await _service.WarmupAsync();
}
[TestCleanup]
public void Cleanup() => _service.Reset();
}
実行順序
- アセンブリ初期化 -
[AssemblyInitialize](テストアセンブリごと 1 回) - クラス初期化 -
[ClassInitialize](テストクラスごと 1 回) - テスト初期化 (すべてのテストメソッド):
- コンストラクタ
TestContextプロパティを設定[TestInitialize]
- テスト実行 - テストメソッドが実行される
- テストクリーンアップ (すべてのテストメソッド):
[TestCleanup]DisposeAsync(実装されている場合)Dispose(実装されている場合)
- クラスクリーンアップ -
[ClassCleanup](テストクラスごと 1 回) - アセンブリクリーンアップ -
[AssemblyCleanup](テストアセンブリごと 1 回)
モダンなアサーション API
MSTest は 3 つのアサーションクラスを提供します: Assert、StringAssert、CollectionAssert。
Assert クラス - コアアサーション
// 等価性
Assert.AreEqual(expected, actual);
Assert.AreNotEqual(notExpected, actual);
Assert.AreSame(expectedObject, actualObject); // 参照等価性
Assert.AreNotSame(notExpectedObject, actualObject);
// null チェック
Assert.IsNull(value);
Assert.IsNotNull(value);
// ブール値
Assert.IsTrue(condition);
Assert.IsFalse(condition);
// 失敗/不確定
Assert.Fail("Test failed due to...");
Assert.Inconclusive("Test cannot be completed because...");
例外テスト ([ExpectedException] より推奨)
// Assert.Throws - TException またはその派生型にマッチ
var ex = Assert.Throws<ArgumentException>(() => Method(null));
Assert.AreEqual("Value cannot be null.", ex.Message);
// Assert.ThrowsExactly - 厳密に型にマッチ
var ex = Assert.ThrowsExactly<InvalidOperationException>(() => Method());
// 非同期版
var ex = await Assert.ThrowsAsync<HttpRequestException>(async () => await client.GetAsync(url));
var ex = await Assert.ThrowsExactlyAsync<InvalidOperationException>(async () => await Method());
コレクションアサーション (Assert クラス)
Assert.Contains(expectedItem, collection);
Assert.DoesNotContain(unexpectedItem, collection);
Assert.ContainsSingle(collection); // 厳密に 1 要素
Assert.HasCount(5, collection);
Assert.IsEmpty(collection);
Assert.IsNotEmpty(collection);
文字列アサーション (Assert クラス)
Assert.Contains("expected", actualString);
Assert.StartsWith("prefix", actualString);
Assert.EndsWith("suffix", actualString);
Assert.DoesNotStartWith("prefix", actualString);
Assert.DoesNotEndWith("suffix", actualString);
Assert.MatchesRegex(@"\d{3}-\d{4}", phoneNumber);
Assert.DoesNotMatchRegex(@"\d+", textOnly);
比較アサーション
Assert.IsGreaterThan(lowerBound, actual);
Assert.IsGreaterThanOrEqualTo(lowerBound, actual);
Assert.IsLessThan(upperBound, actual);
Assert.IsLessThanOrEqualTo(upperBound, actual);
Assert.IsInRange(actual, low, high);
Assert.IsPositive(number);
Assert.IsNegative(number);
型アサーション
// MSTest 3.x - out パラメータを使用
Assert.IsInstanceOfType<MyClass>(obj, out var typed);
typed.DoSomething();
// MSTest 4.x - 型付き結果を直接返す
var typed = Assert.IsInstanceOfType<MyClass>(obj);
typed.DoSomething();
Assert.IsNotInstanceOfType<WrongType>(obj);
Assert.That (MSTest 4.0+)
Assert.That(result.Count > 0); // 失敗メッセージの式を自動キャプチャ
StringAssert クラス
注記: 利用可能な場合は
Assertクラスの同等メソッドを推奨します (例:StringAssert.Contains(actual, "expected")よりAssert.Contains("expected", actual))。
StringAssert.Contains(actualString, "expected");
StringAssert.StartsWith(actualString, "prefix");
StringAssert.EndsWith(actualString, "suffix");
StringAssert.Matches(actualString, new Regex(@"\d{3}-\d{4}"));
StringAssert.DoesNotMatch(actualString, new Regex(@"\d+"));
CollectionAssert クラス
注記: 利用可能な場合は
Assertクラスの同等メソッドを推奨します (例:Assert.Contains)。
// 包含
CollectionAssert.Contains(collection, expectedItem);
CollectionAssert.DoesNotContain(collection, unexpectedItem);
// 等価性 (同じ要素、同じ順序)
CollectionAssert.AreEqual(expectedCollection, actualCollection);
CollectionAssert.AreNotEqual(unexpectedCollection, actualCollection);
// 同等性 (同じ要素、任意の順序)
CollectionAssert.AreEquivalent(expectedCollection, actualCollection);
CollectionAssert.AreNotEquivalent(unexpectedCollection, actualCollection);
// サブセットチェック
CollectionAssert.IsSubsetOf(subset, superset);
CollectionAssert.IsNotSubsetOf(notSubset, collection);
// 要素の検証
CollectionAssert.AllItemsAreInstancesOfType(collection, typeof(MyClass));
CollectionAssert.AllItemsAreNotNull(collection);
CollectionAssert.AllItemsAreUnique(collection);
データ駆動テスト
DataRow
[TestMethod]
[DataRow(1, 2, 3)]
[DataRow(0, 0, 0, DisplayName = "Zeros")]
[DataRow(-1, 1, 0, IgnoreMessage = "Known issue #123")] // MSTest 3.8+
public void Add_ReturnsSum(int a, int b, int expected)
{
Assert.AreEqual(expected, Calculator.Add(a, b));
}
DynamicData
データソースは以下のいずれかの型を返します:
IEnumerable<(T1, T2, ...)>(ValueTuple) - 推奨、型安全性を提供 (MSTest 3.7+)IEnumerable<Tuple<T1, T2, ...>>- 型安全性を提供IEnumerable<TestDataRow>- 型安全性とテストメタデータ制御 (表示名、カテゴリ) を提供IEnumerable<object[]>- 最も推奨されない、型安全性なし
注記: 新しいテストデータメソッドを作成する場合は、
IEnumerable<object[]>よりもValueTupleまたはTestDataRowを推奨します。object[]アプローチはコンパイル時の型チェックなし、型ミスマッチからのランタイムエラーが生じる可能性があります。
[TestMethod]
[DynamicData(nameof(TestData))]
public void DynamicTest(int a, int b, int expected)
{
Assert.AreEqual(expected, Calculator.Add(a, b));
}
// ValueTuple - 推奨 (MSTest 3.7+)
public static IEnumerable<(int a, int b, int expected)> TestData =>
[
(1, 2, 3),
(0, 0, 0),
];
// TestDataRow - カスタム表示名やメタデータが必要な場合
public static IEnumerable<TestDataRow<(int a, int b, int expected)>> TestDataWithMetadata =>
[
new((1, 2, 3)) { DisplayName = "Positive numbers" },
new((0, 0, 0)) { DisplayName = "Zeros" },
new((-1, 1, 0)) { DisplayName = "Mixed signs", IgnoreMessage = "Known issue #123" },
];
// IEnumerable<object[]> - 新しいコード向けに非推奨 (型安全性なし)
public static IEnumerable<object[]> LegacyTestData =>
[
[1, 2, 3],
[0, 0, 0],
];
TestContext
TestContext クラスはテスト実行情報、キャンセレーション対応、出力メソッドを提供します。
完全なリファレンスは TestContext ドキュメント をご覧ください。
TestContext へのアクセス
// プロパティ (MSTest は CS8618 を抑制 - nullable または = null を使用しないこと!)
public TestContext TestContext { get; set; }
// コンストラクタインジェクション (MSTest 3.6+) - 不変性のために推奨
[TestClass]
public sealed class MyTests
{
private readonly TestContext _testContext;
public MyTests(TestContext testContext)
{
_testContext = testContext;
}
}
// スタティックメソッドはパラメータとして受け取る
[ClassInitialize]
public static void ClassInit(TestContext context) { }
// クリーンアップメソッド向けにオプション (MSTest 3.6+)
[ClassCleanup]
public static void ClassCleanup(TestContext context) { }
[AssemblyCleanup]
public static void AssemblyCleanup(TestContext context) { }
キャンセレーショントークン
[Timeout] との協調キャンセレーションのため常に TestContext.CancellationToken を使用します:
[TestMethod]
[Timeout(5000)]
public async Task LongRunningTest()
{
await _httpClient.GetAsync(url, TestContext.CancellationToken);
}
テスト実行プロパティ
TestContext.TestName // 現在のテストメソッド名
TestContext.TestDisplayName // 表示名 (3.7+)
TestContext.CurrentTestOutcome // Pass/Fail/InProgress
TestContext.TestData // パラメータ化テストデータ (3.7+, TestInitialize/Cleanup で)
TestContext.TestException // テストが失敗した場合の例外 (3.7+, TestCleanup で)
TestContext.DeploymentDirectory // デプロイメント項目を含むディレクトリ
出力と結果ファイル
// テスト出力に書き込み (デバッグに便利)
TestContext.WriteLine("Processing item {0}", itemId);
// テスト結果にファイルを添付 (ログ、スクリーンショット)
TestContext.AddResultFile(screenshotPath);
// テストメソッド間でデータを保存/取得
TestContext.Properties["SharedKey"] = computedValue;
アドバンスド機能
不安定なテストのリトライ (MSTest 3.9+)
[TestMethod]
[Retry(3)]
public void FlakyTest() { }
条件付き実行 (MSTest 3.10+)
OS または CI 環境に基づいてテストをスキップまたは実行:
// OS 固有テスト
[TestMethod]
[OSCondition(OperatingSystems.Windows)]
public void WindowsOnlyTest() { }
[TestMethod]
[OSCondition(OperatingSystems.Linux | OperatingSystems.MacOS)]
public void UnixOnlyTest() { }
[TestMethod]
[OSCondition(ConditionMode.Exclude, OperatingSystems.Windows)]
public void SkipOnWindowsTest() { }
// CI 環境テスト
[TestMethod]
[CICondition] // CI でのみ実行 (デフォルト: ConditionMode.Include)
public void CIOnlyTest() { }
[TestMethod]
[CICondition(ConditionMode.Exclude)] // CI では スキップ、ローカルで実行
public void LocalOnlyTest() { }
並列化
// アセンブリレベル
[assembly: Parallelize(Workers = 4, Scope = ExecutionScope.MethodLevel)]
// 特定のクラスに対して無効化
[TestClass]
[DoNotParallelize]
public sealed class SequentialTests { }
作業項目の追跡 (MSTest 3.8+)
テストレポートの追跡可能性のため、テストを作業項目にリンク:
// Azure DevOps 作業項目
[TestMethod]
[WorkItem(12345)] // 作業項目 #12345 にリンク
public void Feature_Scenario_ExpectedBehavior() { }
// 複数の作業項目
[TestMethod]
[WorkItem(12345)]
[WorkItem(67890)]
public void Feature_CoversMultipleRequirements() { }
// GitHub issues (MSTest 3.8+)
[TestMethod]
[GitHubWorkItem("https://github.com/owner/repo/issues/42")]
public void BugFix_Issue42_IsResolved() { }
作業項目の関連付けはテスト結果に表示され、以下に使用できます:
- 要件へのテストカバレッジの追跡
- リグレッション テストへのバグフィックスのリンク
- CI/CD パイプラインの追跡可能性レポート生成
避けるべき一般的な誤り
// ❌ 引数の順序が間違い
Assert.AreEqual(actual, expected);
// ✅ 正解
Assert.AreEqual(expected, actual);
// ❌ ExpectedException を使用 (廃止)
[ExpectedException(typeof(ArgumentException))]
// ✅ Assert.Throws を使用
Assert.Throws<ArgumentException>(() => Method());
// ❌ LINQ Single() を使用 - 例外が不明確
var item = items.Single();
// ✅ ContainsSingle を使用 - より良い失敗メッセージ
var item = Assert.ContainsSingle(items);
// ❌ 強制キャスト - 例外が不明確
var handler = (MyHandler)result;
// ✅ 型アサーション - 失敗時に実際の型を表示
var handler = Assert.IsInstanceOfType<MyHandler>(result);
// ❌ キャンセレーショントークンを無視
await client.GetAsync(url, CancellationToken.None);
// ✅ テストキャンセレーションをフロー
await client.GetAsync(url, TestContext.CancellationToken);
// ❌ TestContext を nullable にする - 不要な null チェックにつながる
public TestContext? TestContext { get; set; }
// ❌ null! を使用 - MSTest はすでにこのプロパティの CS8618 を抑制
public TestContext TestContext { get; set; } = null!;
// ✅ nullable または初期化子なしで宣言 - MSTest が警告を処理
public TestContext TestContext { get; set; }
テスト整理
- 機能またはコンポーネントでテストをグループ化
- フィルタリングのため
[TestCategory("Category")]を使用 - カスタムメタデータのため
[TestProperty("Name", "Value")]を使用 (例:[TestProperty("Bug", "12345")]) - クリティカルテストのため
[Priority(1)]を使用 - 関連する MSTest アナライザーを有効化 (コンストラクタ推奨のための MSTEST0020)
モッキングと分離
- 依存関係のモッキングに Moq または NSubstitute を使用
- モッキングを容易にするためインターフェースを使用
- テスト対象ユニットを分離するため依存関係をモック
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- github
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/github/awesome-copilot / ライセンス: MIT
関連スキル
hugging-face-trackio
Trackioを使用してMLトレーニング実験を追跡・可視化できます。トレーニング中のメトリクスログ記録(Python API)、トレーニング診断のアラート発火、ログされたメトリクスの取得・分析(CLI)が必要な場合に活用してください。リアルタイムダッシュボード表示、Webhookを使用したアラート、HF Space同期、自動化向けのJSON出力に対応しています。
btc-bottom-model
ビットコインのサイクルタイミングモデルで、加重スコアリングシステムを搭載しています。日次パルス(4指標、32ポイント)とウィークリー構造(9指標、68ポイント)の2カテゴリーにわたる13の指標を追跡し、0~100のマーケットヒートスコアを算出します。ETFフロー、ファンディングレート、ロング/ショート比率、恐怖・貪欲指数、LTH-MVRV、NUPL、SOPR(LTH+STH)、LTH供給率、移動平均倍率(365日MA、200週MA)、週次RSI、出来高トレンドに対応します。市場サイクル全体を通じて買いと売りの両方の推奨を提供します。ビットコインの底値拾い、BTCサイクルポジション、買い時・売り時、オンチェーン指標、MVRV、NUPL、SOPR、LTH動向、ETFの流出入、ファンディングレート、恐怖指数、ビットコインが過熱状態か、マイナーコスト、暗号資産市場のセンチメント、BTCのポジションサイジング、「今ビットコインを買うべきか」「BTCが天井をつけているか」「オンチェーン指標は何を示しているか」といった質問の際にこのスキルを活用します。
protein_solubility_optimization
タンパク質の溶解性最適化 - タンパク質の溶解性を最適化します。タンパク質の特性を計算し、溶解性と親水性を予測し、有効な変異を提案します。タンパク質配列の特性計算、タンパク質機能の予測、親水性計算、ゼロショット配列予測を含むタンパク質エンジニアリング業務に使用できます。3つのSCPサーバーから4つのツールを統合しています。
research-lookup
Parallel Chat APIまたはPerplexity sonar-pro-searchを使用して、最新の研究情報を検索できます。学術論文の検索にも対応しています。クエリは自動的に最適なバックエンドにルーティングされるため、論文の検索、研究データの収集、科学情報の検証に活用できます。
tree-formatting
ggtree(R)またはiTOL(ウェブ)を使用して、系統樹の可視化とフォーマットを行います。系統樹を図として描画する際、ツリーレイアウトの選択、分類学に基づく枝やラベルの色付け、クレードの折りたたみ、サポート値の表示、またはツリーへのオーバーレイ追加が必要な場合に使用してください。系統推定(protein-phylogenyスキルを使用)やドメイン注釈(今後の独立したスキル)には使用しないでください。
querying-indonesian-gov-data
インドネシア政府の50以上のAPIとデータソースに接続できます。BPJPH(ハラール認証)、BOM(食品安全)、OJK(金融適正性)、BPS(統計)、BMKG(気象・地震)、インドネシア中央銀行(為替レート)、IDX(株式)、CKAN公開データポータル、pasal.id(第三者法MCP)に対応しています。インドネシア政府データを活用したアプリ開発、.go.idウェブサイトのスクレイピング、ハラール認証の確認、企業の法的適正性の検証、金融機関ステータスの照会、またはインドネシアMCPサーバーへの接続時に使用できます。CSRF処理、CKAN API使用方法、IP制限回避など、すぐに実行可能なPythonパターンを含んでいます。