在我的测试中,连接字符串在第一次调用数据库后为空。为什么?

In my test, the connection string is blank after the first call to the database. Why?

我正在使用 XUnit、FakeItEasy 和 Dapper。我正在测试 .NET Core 2.1 WebAPI 调用。当我启动实际网站时,我没有任何错误。我的测试似乎有问题。

对于 XUnit,我使用的是 DatabaseFixture,如下所示:

public class DatabaseFixture : IDisposable
{
    public DatabaseFixture()
    {
        Settings = GetSettings();
        var serviceProvider = CreateServices();

        using (var scope = serviceProvider.CreateScope())
        {
            EnsureDatabase();
            UpdateDatabase(scope.ServiceProvider);
            Db = new SqlConnection(Settings.TestDbConnectionString);
        }
    }
    ...

我的网络控制器如下所示:

    public async Task<ActionResult> Authorization()
    {
        ...
        var user = await _userRepository.FindBySubject(subject);  // <== First call to DB, all good
        if (user == null) return Ok(new { UserNotRegistered = true });

        var roles = await _userRepository.GetRoles(subject); // <== Second call to DB, ConnectionString off of Fake is ""
        ....

        return Ok(roles);
    }

UserRepo 看起来像这样:

public class UserRepository 
{
    ....
    public async Task<Membership> FindByNameAsync(string subject_cn, CancellationToken cancellationToken)
    {
        using (var connection = _connectionFactory.GetConnection())
        {
            return await connection.QuerySingleOrDefaultAsync<Membership>($@"SQL Code", new {subject_cn});
        }
    }

    public async Task<Membership> FindBySubject(string subject_cn)
    {
        return await FindByNameAsync(subject_cn, new CancellationToken());  // First call, all good
    }

    public async Task<IList<string>> GetRoles(string subject_cn)
    {
        var membership = await FindBySubject(subject_cn); //Second call, no connection string :(
        return await GetRolesAsync(membership, new CancellationToken());
    }

最后也是最重要的,我的测试:

[Collection(nameof(DatabaseFixture))]
public class UserControllerTests
{
    private readonly IDatabaseConnectionFactory _connectionFactory;
    public UserControllerTests(DatabaseFixture fixture)
    {
        _connectionFactory = A.Fake<IDatabaseConnectionFactory>();
        A.CallTo(() => _connectionFactory.GetConnection()).Returns(fixture.Db);
    }

    [Fact]
    public async Task Authorize_ReturnsRoles()
    {
        var configurationManager = A.Fake<IConfigurationManager>();
        A.CallTo(() => configurationManager.GetSettings()).Returns(new Web.Settings() { ... stuff ... });

        var authenticationManager = A.Fake<IAuthenticationManager>();

        var userController = new UserController(new UserRepository(_connectionFactory), authenticationManager, configurationManager);

        var response = await userController.Authorization(); // Connection string is empty on second data call
        var viewResult = Assert.IsType<ViewResult>(response);
        var model = Assert.IsAssignableFrom<AuthorizationResult>(viewResult);

        Assert.Contains("A Role", model.Roles);
        Assert.Equal(AuthorizationResult.UserState.Authenticated, model.Status);
        A.CallTo(() => authenticationManager.AddToRoles(A.Fake<Membership>(), model.Roles)).MustHaveHappened();
        A.CallTo(() => authenticationManager.SignIn(A.Fake<Membership>())).MustHaveHappened();
    }
}

我不确定 "forgetting" 连接字符串是如何伪造的。返回的具体错误是:Message: System.InvalidOperationException : The ConnectionString property has not been initialized. 当我在第一次调用后进行调试时,果然连接对象上的连接字符串为空。任何人都可以阐明这种情况吗?

我不确定到底发生了什么。我认为问题不在于 FakeItEasy,因为连接本身不是假的。作为一种变通方法,您可以做的是为每个调用使假连接工厂 return 成为一个新连接:

A.CallTo(() => _connectionFactory.GetConnection())
    .ReturnsLazily(() => new SqlConnection(settings.TestDbConnectionString)).