I'm using XUnit, FakeItEasy and Dapper. I'm testing a .NET Core 2.1 WebAPI call. When I spin up the actual web site, I have no errors. Something seems to be wrong with my test.
For XUnit I'm using a DatabaseFixture like so:
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);
}
}
...
My web controller looks like this:
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 looks like this:
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());
}
And finally and probably most important, my test:
[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();
}
}
I'm not sure how the fake is "forgetting" the connection string. The specific error being returned is: Message: System.InvalidOperationException : The ConnectionString property has not been initialized.
When I debug after the first call, sure enough the connection string on the connection object is blank. Can anyone shed some light on this situation?