如何在 xUnit 和 nSubstitute 中对服务调用进行单元测试

How to unit test a service call in xUnit and nSubstitute

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

我正在使用 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());
    }
}

我的拉力赛服务 class 对数据库进行简单调用以获取所有拉力赛实体和 returns 那些:

public class RallyService : IRallyService
{
    private readonly RallyDbContext _context;

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

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

如有任何指导,我们将不胜感激。

我不认为单元测试构造函数带有参数是标准的。单元测试 运行ner 将更新此 class,除非您使用的是自动注入该参数的东西,否则我认为测试将失败 运行。

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

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() { /* ... */ }
}

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

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

由于您使用 .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。