【问题标题】:How to unit test a service call in xUnit and nSubstitute如何在 xUnit 和 nSubstitute 中对服务调用进行单元测试
【发布时间】:2018-05-23 08:05:44
【问题描述】:

我一直试图弄清楚如何对服务进行单元测试,但到目前为止一无所获。

我正在使用 xUnit 和 NSubstitute(按照朋友的建议),下面是我想要运行的简单测试(目前失败)。

public class UnitTest1
{
    private readonly RallyService _rallyService;

    public UnitTest1(RallyService rallyService)
    {
        _rallyService= rallyService;
    }

    [Fact]
    public void Test1()
    {
        var result = _rallyService.GetAllRallies();

        Assert.Equal(2, result.Count());
    }
}

我的拉力赛服务类对 db 进行简单调用以获取所有拉力赛实体并返回这些:

public class RallyService : IRallyService
{
    private readonly RallyDbContext _context;

    public RallyService(RallyDbContext context)
    {
        _context = context;
    }

    public IEnumerable<Rally> GetAllRallies()
    {
        return _context.Rallies;
    }
}

任何指导将不胜感激。

【问题讨论】:

标签: unit-testing asp.net-core nunit nsubstitute


【解决方案1】:

我不认为有一个带参数的单元测试构造函数是标准的。单元测试运行器将新建这个类,除非您使用会自动注入该参数的东西,否则我认为测试将无法运行。

这是一个标准的夹具布局:

public class SampleFixture {

    [Fact]
    public void SampleShouldWork() {
        // Arrange stuff we need for the test. This may involved configuring
        // some dependencies, and also creating the subject we are testing.
        var realOrSubstitutedDependency = new FakeDependency();
        realOrSubstitutedDependency.WorkingItemCount = 42;
        var subject = new Subject(realOrSubstitutedDependency);

        // Act: perform the operation we are testing
        var result = subject.DoWork();

        // Assert: check the subject's operation worked as expected
        Assert.Equal(42, result);
    }

    [Fact]
    public void AnotherTest() { /* ... */ }
}

如果您需要在测试之间进行通用设置,您可以使用无参数构造函数并在那里进行通用初始化。

就您要测试的特定类而言,您需要确保您的RallyDbContext 处于已知状态以进行可重复且可靠的测试。您可能需要查找特定于测试实体框架的答案以获取更多信息。

【讨论】:

    【解决方案2】:

    由于您使用 .NET Core,我假设您也使用 Entity Framework Core。虽然可以模拟以前 EF 版本中的大多数操作,但 EF Core 建议使用in-memory database 进行单元测试。 IE。您不需要模拟RallyDbContext,因此此特定测试不需要NSubstitute。在使用服务测试控制器或应用程序时,您需要 NSubstitute 来模拟服务。

    下面是您使用内存数据库编写的Test1

    public class UnitTest1
    {
        private readonly DbContextOptions<RallyDbContext> _options;
    
        public UnitTest1()
        {
            // Use GUID for in-memory DB names to prevent any possible name conflicts
            _options = new DbContextOptionsBuilder<RallyDbContext>()
                .UseInMemoryDatabase(Guid.NewGuid().ToString())
                .Options;
        }
    
        [Fact]
        public async Task Test1()
        {
            using (var context = new RallyDbContext(_options))
            {
                //Given 2 records in database
                await context.AddRangeAsync(new Rally { Name = "rally1" }, new Rally { Name = "rally2" });
                await context.SaveChangesAsync();
            }
    
            using (var context = new RallyDbContext(_options))
            {
                //When retrieve all rally records from the database
                var service = new RallyService(context);
                var rallies = service.GetAllRallies();
    
                //Then records count should be 2
                Assert.Equal(2, rallies.Count());
            }
        }
    }
    

    我的GitHub 中有一个带有此单元测试的工作测试应用程序供您参考。我在实际应用中使用了 SQL Express。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-10
      • 1970-01-01
      • 2021-12-03
      • 1970-01-01
      • 2021-10-20
      • 2018-10-20
      相关资源
      最近更新 更多