Skills Plugins MCP Prompt Model 博客 我的中心

csharp-testing

xUnit、FluentAssertions、モッキング、統合テスト、テスト組織のベストプラクティスを使用したC#と.NETのテストパターン。

DeepseekModel キュレーション済みスキル 品質 優秀 · 90 v1.0.0

取得

https://deepseekmodel.com/api/download.php?id=affaan-m-ecc-docs-ja-jp-skills-csharp-testing-skill-md&format=skill
ダウンロード .skill 標準形式。system_prompt と model_config を収録し、任意の Agent で利用可能
.skill ファイルの system_prompt フィールドの実際の内容。
name csharp-testing description xUnit、FluentAssertions、モッキング、統合テスト、テスト組織のベストプラクティスを使用したC#と.NETのテストパターン。 origin ECC C#テストパターン xUnit、FluentAssertions、最新のテストプラクティスを使用した.NETアプリケーションの包括的なテストパターン。 起動条件 C#コードの新しいテストを書く場合 テスト品質とカバレッジのレビュー .NETプロジェクトのテストインフラストラクチャの設定 フレーキーまたは遅いテストのデバッグ テストフレームワークスタック ツール 目的 xUnit テストフレームワーク(.NETに推奨) FluentAssertions 読みやすいアサーション構文 NSubstitute または Moq 依存関係のモッキング Testcontainers 統合テストでの実際のインフラ WebApplicationFactory ASP.NET Core統合テスト Bogus 現実的なテストデータ生成 ユニットテスト構造 Arrange-Act-Assert public sealed class OrderServiceTests { private readonly IOrderRepository _repository = Substitute.For<IOrderRepository>(); private readonly ILogger<OrderService> _logger = Substitute.For<ILogger<OrderService>>(); private readonly OrderService _sut; public OrderServiceTests () { _sut = new OrderService(_repository, _logger); } [ Fact ] public async Task PlaceOrderAsync_ReturnsSuccess_WhenRequestIsValid () { // Arrange var request = new CreateOrderRequest { CustomerId = "cust-123" , Items = [ new OrderItem( "SKU-001" , 2 , 29.99 m)] }; // Act var result = await _sut.PlaceOrderAsync(request, CancellationToken.None); // Assert result.IsSuccess.Should().BeTrue(); result.Value.Should().NotBeNull(); result.Value!.CustomerId.Should().Be( "cust-123" ); } [ Fact ] public async Task PlaceOrderAsync_ReturnsFailure_WhenNoItems () { // Arrange var request = new CreateOrderRequest { CustomerId = "cust-123" , Items = [] }; // Act var result = await _sut.PlaceOrderAsync(request, CancellationToken.None); // Assert result.IsSuccess.Should().BeFalse(); result.Error.Should().Contain( "at least one item" ); } } Theoryによるパラメータ化テスト [ Theory ] [ InlineData( "" , false) ] [ InlineData( "a" , false) ] [ InlineData( "ab@c.d" , false) ] [ InlineData( "user@example.com" , true) ] [ InlineData( "user+tag@example.co.uk" , true) ] public void IsValidEmail_ReturnsExpected ( string email, bool expected ) { EmailValidator.IsValid(email).Should().Be(expected); } [ Theory ] [ MemberData(nameof(InvalidOrderCases)) ] public async Task PlaceOrderAsync_RejectsInvalidOrders ( CreateOrderRequest request, string expectedError ) { var result = await _sut.PlaceOrderAsync(request, CancellationToken.None); result.IsSuccess.Should().BeFalse(); result.Error.Should().Contain(expectedError); } public static TheoryData<CreateOrderRequest, string > InvalidOrderCases => new () { { new () { CustomerId = "" , Items = [ValidItem()] }, "CustomerId" }, { new () { CustomerId = "c1" , Items = [] }, "at least one item" }, { new () { CustomerId = "c1" , Items = [ new ( "" , 1 , 10 m)] }, "SKU" }, }; NSubstituteによるモッキング [ Fact ] public async Task GetOrderAsync_ReturnsNull_WhenNotFound () { // Arrange var orderId = Guid.NewGuid(); _repository.FindByIdAsync(orderId, Arg.Any<CancellationToken>()) .Returns((Order?) null ); // Act var result = await _sut.GetOrderAsync(orderId, CancellationToken.None); // Assert result.Should().BeNull(); } [ Fact ] public async Task PlaceOrderAsync_PersistsOrder () { // Arrange var request = ValidOrderRequest(); // Act await _sut.PlaceOrderAsync(request, CancellationToken.None); // Assert — リポジトリが呼び出されたことを検証 await _repository.Received( 1 ).AddAsync( Arg.Is<Order>(o => o.CustomerId == request.CustomerId), Arg.Any<CancellationToken>()); } ASP.NET Core統合テスト WebApplicationFactoryのセットアップ public sealed class OrderApiTests : IClassFixture < WebApplicationFactory < Program >> { private readonly HttpClient _client; public OrderApiTests ( WebApplicationFactory<Program> factory ) { _client = factory.WithWebHostBuilder(builder => { builder.ConfigureServices(services => { // テスト用にインメモリDBで実際のDBを置き換え services.RemoveAll<DbContextOptions<AppDbContext>>(); services.AddDbContext<AppDbContext>(options => options.UseInMemoryDatabase( "TestDb" )); }); }).CreateClient(); } [ Fact ] public async Task GetOrder_Returns404_WhenNotFound () { var response = await _client.GetAsync( $"/api/orders/ {Guid.NewGuid()} " ); response.StatusCode.Should().Be(HttpStatusCode.NotFound); } [ Fact ] public async Task CreateOrder_Returns201_WithValidRequest () { var request = new CreateOrderRequest { CustomerId = "cust-1" , Items = [ new ( "SKU-001" , 1 , 19.99 m)] }; var response = await _client.PostAsJsonAsync( "/api/orders" , request); response.StatusCode.Should().Be(HttpStatusCode.Created); response.Headers.Location.Should().NotBeNull(); } } Testcontainersによるテスト public sealed class PostgresOrderRepositoryTests : IAsyncLifetime { private readonly PostgreSqlContainer _postgres = new PostgreSqlBuilder() .WithImage( "postgres:16-alpine" ) .Build(); private AppDbContext _db = null !; public async Task InitializeAsync () { await _postgres.StartAsync(); var options = new DbContextOptionsBuilder<AppDbContext>() .UseNpgsql(_postgres.GetConnectionString()) .Options; _db = new AppDbContext(options); await _db.Database.MigrateAsync(); } public async Task DisposeAsync () { await _db.DisposeAsync(); await _postgres.DisposeAsync(); } [ Fact ] public async Task AddAsync_PersistsOrder () { var repo = new SqlOrderRepository(_db); var order = Order.Create( "cust-1" , [ new OrderItem( "SKU-001" , 2 , 10 m)]); await repo.AddAsync(order, CancellationToken.None); var found = await repo.FindByIdAsync(order.Id, CancellationToken.None); found.Should().NotBeNull(); found!.Items.Should().HaveCount( 1 ); } } テスト組織 tests/ MyApp.UnitTests/ Services/ OrderServiceTests.cs PaymentServiceTests.cs Validators/ EmailValidatorTests.cs MyApp.IntegrationTests/ Api/ OrderApiTests.cs Repositories/ OrderRepositoryTests.cs MyApp.TestHelpers/ Builders/ OrderBuilder.cs Fixtures/ DatabaseFixture.cs テストデータビルダー public sealed class OrderBuilder { private string _customerId = "cust-default" ; private readonly List<OrderItem> _items = [ new ( "SKU-001" , 1 , 10 m)]; public OrderBuilder WithCustomer ( string customerId ) { _customerId = customerId; return this ; } public OrderBuilder WithItem ( string sku, int quantity, decimal price ) { _items.Add( new OrderItem(sku, quantity, price)); return this ; } public Order Build () => Order.Create(_customerId, _items); } // テストでの使用 var order = new OrderBuilder() .WithCustomer( "cust-vip" ) .WithItem( "SKU-PREMIUM" , 3 , 99.99 m) .Build(); よくあるアンチパターン アンチパターン 修正方法 実装の詳細をテストする 動作と結果をテストする 共有の可変テスト状態 テストごとに新しいインスタンス(xUnitはコンストラクタでこれを行う) 非同期テストでの Thread.Sleep タイムアウトまたはポーリングヘルパーを使用した Task.Delay ToString() 出力のアサーション 型付きプロパティのアサーション テストごとに1つの巨大なアサーション テストごとに1つの論理的なアサーション 実装を記述するテスト名 動作で命名: Method_ExpectedResult_WhenCondition CancellationToken を無視する 常に渡してキャンセルを確認する テストの実行 # すべてのテストを実行 dotnet test # カバレッジを付けて実行 dotnet test --collect: "XPlat Code Coverage" # 特定のプロジェクトを実行 dotnet test tests/MyApp.UnitTests/ # テスト名でフィルタリング dotnet test --filter "FullyQualifiedName~OrderService" # 開発中のウォッチモード dotnet watch test --project tests/MyApp.UnitTests/
このスキルを起動するキーワード。クリックでコピーできます。

このスキルにはトリガーワードがありません。

ダウンロードした .skill に含まれるフィールド。
フィールド 説明
formatフォーマット識別子(skill/v1)
skill_idスキル固有 ID
nameスキル名
versionバージョン
description説明
categoryカテゴリ(配列)
trigger_wordsトリガーワード
tagsタグ
sourceソース
source_urlソース URL(本ページ)
exported_atエクスポート日時(ダウンロード毎)
system_promptシステムプロンプト本文
model_configモデル設定:provider / model / temperature / max_tokens / top_p
examplesサンプル
install_guide各プラットフォームの導入説明(Coze / Dify / Claude / カスタム)
同じスキルを各プラットフォーム形式で出力できます。
.skill 標準形式。system_prompt と model_config を収録し、任意の Agent で利用可能 ダウンロード
.skillpro 拡張形式。scripts / tools / dependencies / hooks を含む ダウンロード
.json 純粋な JSON 出力。system_prompt とモデル設定のみ ダウンロード
Coze frontmatter 付き Markdown。Coze へのインポート用 ダウンロード
Dify Dify DSL。アプリ作成後にそのままインポート ダウンロード

每日精选 Skill 推荐,免费送到你邮箱

输入邮箱,每天接收一个精选 AI Agent 技能推荐。完全免费,持续更新。

提交后我们会发送一封确认邮件,点击邮件里的链接才会开始收信。

完全免费,取消任意时间。我们不会发送垃圾邮件。