繁体   English   中英

为 Web Api in.Net 编写单元测试用例

[英]Writing Unit Test cases for Web Api in .Net

我想为 my.Net 项目编写单元测试用例。 这就是我的 Controller 的样子

using backend.Models;
using backend.services;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

namespace backend.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class GuestTypeController : ControllerBase
    {
        private readonly GuestTypeService _guestType;
        public GuestTypeController(GuestTypeService _guestType)
        {
            this._guestType = _guestType;

        }
        [HttpGet("GuestType")]

        
         public List<GuestType> guestType()
        {

            return _guestType.getGuestType();
        }
    }
}


这就是服务 class 的样子


namespace backend.services
{
    public class GuestTypeService
    {
        private readonly bookingengineContext dbContext;
        public GuestTypeService(bookingengineContext dbContext)
        {
            this.dbContext = dbContext;
        }

        public List<GuestType> getGuestType()
        {
              
            return dbContext.GuestTypes.ToList();
        }
    }
}

我的 controller 的构造函数中有 object 服务。 在编写测试用例时,我将我的 controller 和 mocking 称为我的数据库上下文和服务 class。 但由于我的 controller 在构造函数中包含服务 class object 我无法对其进行测试。 测试我的控制器的方法是什么。 这是我第一次写单元测试。 所以我很挣扎。

这样测试实际上更容易 您可以创建所需的 object 实例。 您甚至不必模拟 DbContext。 您可以在 memory 模式下创建一个针对内存提供程序或 SQLite 的提供程序。 EF Core 文档有一个部分解释了可用的测试选项,包括test doubles的各种选项。

存储库,或者至少是接口

Repository 选项并不意味着使用完整的 CRUD 方法创建名为IRepository的接口。 这意味着抽象实际的数据访问,允许它在不修改程序的rest的情况下进行更改。 在这种情况下,您的服务正在这样做。 如果服务实现了一个接口,您可以模拟它或创建虚拟测试服务:

public interface IGuestTypeService
{
    List<GuestType> GetGuestTypes();
}

public GuestTypeService:IGuestTypeService
{
    ...
    public List<GuestType> GetGuestTypes()
    {
        ....
    }
}

该服务应通过其接口注册:

serviced.AddScoped<IGuestTypeService,GuestTypeService>();

并且容器应该接受接口

public class GuestTypeController : ControllerBase
{
    private readonly IGuestTypeService _guestType;
    public GuestTypeController(IGuestTypeService _guestType)
    {
        this._guestType = _guestType;
    }

在您的测试中,您可以创建一个虚拟测试服务:

class DummyService:IGuestService
{
    public List<GuestType> GuestTypes{get;set;}

    public List<GuestType> GetGuestType()=>GuestTypes;
}


[Fact]
public void MyTest()
{
    var guestTypes=new List<GuestType>{ ....};
    var service=new DummyService {GuestTypes = guestTypes};

    var controller=new GuestTypeController(service);

    var actual=controller.getGuestType();

    Assert.Equal(actual,guestTypes);
}

测试 DbContext

也可以在内存模式或 memory 集合中创建由 SQLite 支持的 DbContext。 SQLite 提供完整的 SQL 支持,而内存提供程序本质上是一个包装列表,并在复杂操作中分解。

SQLite 内存部分中解释了使用 SQLite 进行的测试。

在这种情况下,测试会创建并加载 DbContext 并将其注入到实际服务中:

public class MyTestClass:IDisposable
{
    SQLiteConnection _connection;
    DbContextOptions<bookingengineContext> _contextOptions;

    public MyTestClass()
    {
        // Create and open a connection. This creates the SQLite in-memory database, which will persist until the connection is closed
        // at the end of the test (see Dispose below).
        _connection = new SqliteConnection("Filename=:memory:");
        _connection.Open();

        // These options will be used by the context instances in this test suite, including the connection opened above.
        _contextOptions = new DbContextOptionsBuilder<bookingengineContext>()
            .UseSqlite(_connection)
            .Options;

        SeedData();
    }


 
    public void Dispose() => _connection.Dispose();

    bookingengineContext CreateContext() => new bookingengineContext(_contextOptions);

测试数据通过SeedData()插入数据库

void SeedData()
{
    var data=new[]
    {
        new GuestType { ... },
        new GuestType { ... }
    };

    using var context = new bookingengineContext(_contextOptions);
    context.Database.EnsureCreated();
    context.AddRange(data);
    context.SaveChanges();
}

测试可以根据需要在内存数据库之上创建一个新的 DbContext。 实际测试与之前的测试并没有什么不同

[Fact]
public void MyTest()
{
    using var db=CreateContext();
    var service=new GuestTypeService(db);

    var controller=new GuestTypeController(service);

    var actual=controller.getGuestType();

    var expected=db.GuestTypes.ToList();

    Assert.Equal(actual,expected);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM