【ASP.NET Core】【xUnit】【Moq】단위 테스트 추가 1

23008 단어 csharpaspnetcorexunit

소개



ASP.NET Core 프로젝트에서 단위 테스트를 추가하려고 합니다.
이번에는 xUnit과 Moq를 사용합니다.

환경


  • .NET 코어 버전 3.1.402
  • xUnit 버전 2.4.0
  • 모크 ver.4.14.5

  • 기본 프로젝트



    "dotnet new empty -n XUnitSample"로 ASP.NET Core 프로젝트를 만들고 일부 클래스를 추가했습니다.

    Startup.cs



    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting;
    using Services;
    
    namespace XUnitSample
    {
        public class Startup
        {
            public void ConfigureServices(IServiceCollection services)
            {
                services.AddRazorPages();
                services.AddControllers();
                services.AddScoped<IProductService, ProductService>();
            }
            public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
                app.UseRouting();
                app.UseStaticFiles();
                app.UseEndpoints(endpoints =>
                {
                    endpoints.MapControllers();
                });
            }
        }
    }
    

    Product.cs



    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    
    namespace Models
    {
        [Table("Product")]
        public class Product
        {
            [Key]
            public int Id { get; set; }
            public string? ModelName { get; set; }
        }
    }
    

    HomeController.cs



    using System.Collections.Generic;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Mvc;
    using Models;
    using Services;
    
    namespace Controllers
    {
        public class HomeController: Controller
        {
            private readonly IProductService _product;
            public HomeController(IProductService product)
            {
                _product = product;
            }
            [Route("/")]
            public IActionResult Index()
            {
                ViewData["Title"] = "Home";
                return View("Views/Index.cshtml");
            }
            [Route("/Products/All")]
            public async Task<List<Product>> GetAllProducts()
            {
                return await _product.GetProductsAsync();
            }
        }
    }
    

    IProductService.cs



    using System.Collections.Generic;
    using System.Threading.Tasks;
    using Models;
    
    namespace Services
    {
        public interface IProductService
        {
            Task<List<Product>> GetProductsAsync();
        }
    }
    

    ProductService.cs



    using System.Collections.Generic;
    using System.Threading.Tasks;
    using Models;
    
    namespace Services
    {
        public class ProductService: IProductService
        {
            public async Task<List<Product>> GetProductsAsync()
            {
                return await Task.FromResult(new List<Product>{
                    new Product { Id = 0, ModelName = "SampleModel" }
                });
            }
        }
    }
    

    _Layout.cshtml



    <!DOCTYPE html>
    <html lang="ja">
    <head>
        <meta charset="utf-8" />
        <title>@ViewData["Title"]</title>
    </head>
    <body>
        @RenderBody()
    </body>
    </html>
    

    Index.cshtml



    <div>Hello World</div>
    

    테스트 프로젝트 추가



    먼저 테스트 프로젝트를 추가합니다.
    하지만 기존 프로젝트에 추가할 수 없거나 오류가 발생합니다.


    obj\Debug\netcoreapp3.1\.NETCoreApp,Version=v3.1.AssemblyAttributes.cs(4,12): error CS0579: Duplicate 'global::System.Runtime.Versioning.TargetFrameworkAttribute' attribute [C:\Users\example\OneDrive\Documents\workspace\Dotnet31\AspNetCore31Sample\AspNetCore31Sample.csproj]
    obj\Debug\netcoreapp3.1\AspNetCore31Sample.AssemblyInfo.cs(13,12): error CS0579: Duplicate 'System.Reflection.AssemblyCompanyAttribute' attribute 
    ...
    

    따라서 솔루션을 만들고 이러한 프로젝트를 여기에 넣어야 합니다.

    dotnet new sln -n XUnit
    dotnet sln add XUnitSample
    

  • dotnet sln command - .NET Core CLI | Microsoft Docs

  • xUnit 프로젝트 추가



    이제 "xunit"템플릿으로 테스트 프로젝트를 만들 수 있습니다.

    dotnet new xunit -n XUnitSampleTest
    dotnet sln add XUnitSampleTest
    dotnet add reference ../XUnitSample/XUnitSample.csproj
    



    모의를 사용하기 위해 Moq를 추가합니다.

    XUnitSampleTest.csproj



    <Project Sdk="Microsoft.NET.Sdk">
      <PropertyGroup>
        <TargetFramework>netcoreapp3.1</TargetFramework>
        <IsPackable>false</IsPackable>
      </PropertyGroup>
      <ItemGroup>
        <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0"/>
        <PackageReference Include="xunit" Version="2.4.0"/>
        <PackageReference Include="xunit.runner.visualstudio" Version="2.4.0"/>
        <PackageReference Include="coverlet.collector" Version="1.2.0"/>
        <PackageReference Include="Moq" Version="4.14.5"/>
      </ItemGroup>
      <ItemGroup>
        <ProjectReference Include="..\XUnitSample\XUnitSample.csproj"/>
      </ItemGroup>
    </Project>
    

    테스트 클래스 만들기



    "HomeController"를 테스트하기 위한 테스트 클래스를 추가합니다.

    HomeControllerTest.cs



    using System.Collections.Generic;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Mvc;
    using Models;
    using Moq;
    using Services;
    using Xunit;
    
    namespace Controllers
    {
        public class HomeControllerTest
        {
            private readonly HomeController _target;
            public HomeControllerTest()
            {
                var productMock = new Mock<IProductService>();
                productMock.Setup(p => p.GetProductsAsync())
                    .ReturnsAsync(new List<Product>
                    {
                        new Product
                        {
                            Id = 1,
                            ModelName = "ModelTest"
                        }
                    });
                _target = new HomeController(productMock.Object);
            }
            [Fact]
            public async Task GetAllProductsReturnsOneItem()
            {
                Assert.True((await _target.GetAllProducts()).Count == 1);
            }
            [Fact]
            public void IndexReturnsView()
            {
                Assert.IsType<ViewResult>(_target.Index());
            }
            [Fact]
            public void PageTitleIsHome()
            {
                var page = _target.Index();
                var viewResult = Assert.IsType<ViewResult>(page);
                Assert.Equal("Home", viewResult.ViewData["Title"].ToString());
            }
        }
    }
    

    "dotnet test"로 테스트 결과를 얻을 수 있습니다.


    Visual Studio Code로 테스트 실행



    "dotnet test"명령의 결과에 문제가 없지만 여전히 아래와 같은 UI를 원합니다.



    그래서 Visual Studio Code에 몇 가지 확장을 추가합니다.
  • Test Explorer UI - Visual Studio Marketplace
  • .NET Core Test Explorer - Visual Studio Marketplace

  • ".NET Core 테스트 탐색기"라는 두 가지 확장이 있습니다.
    하지만 저는 this 을 좋아합니다. 테스트를 실행하기 전에 프로젝트를 빌드하고 테스트를 수동으로 업데이트할 필요가 없기 때문입니다.

    자원


  • Home > xUnit.net
  • Getting started: .NET Core with command line > xUnit.net
  • Moq : Mocking Framework for .NET - Qiita
  • GitHub - moq/moq4: Repo for managing Moq 4.x
  • Unit testing C# code in .NET Core using dotnet test and xUnit - .NET Core | Microsoft Docs
  • Test controller logic in ASP.NET Core | Microsoft Docs
  • c# - What's the idiomatic way to verify collection size in xUnit? - Stack Overflow
  • 좋은 웹페이지 즐겨찾기