我编写了一些与PostgreSQL一起使用的已创建系统的测试。我在解决方案中创建了类型为Class Library(.NET Core)的新项目。然后,我创建了一个类,它测试类DocumentRepository。但是在DocumentRepository的构造函数中使用IConfiguration(用于连接数据库),而这个IConfiguration我不能在测试类中调用。我如何在UnitTest中模仿与数据库的连接?
这个课,我想测试
public class DocumentsRepository : IRepository<Documents>
{
private string connectionString;
public DocumentsRepository(IConfiguration configuration, string login, string password)
{
connectionString = configuration.GetValue<string>("DBInfo:ConnectionString");
connectionString = connectionString.Replace("username", login);
connectionString = connectionString.Replace("userpassword", password);
}
internal IDbConnection Connection
{
get
{
return new NpgsqlConnection(connectionString);
}
}
public void Add(Documents item)
{
using (IDbConnection dbConnection = Connection)
{
dbConnection.Open();
dbConnection.Execute("SELECT addrecuserdocuments(@DocumentName,@Contents,@DocumentIntroNumber)", item);
}
}
此处测试,我尝试使用
using FluentAssertions;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using WebApplication4.Controllers;
using WebApplication4.Entites;
using WebApplication4.ViewModels;
using Xunit;
namespace TestsApp
{
public class UserControllerTest
{
private IConfiguration configuration;
private string connectionString;
[Fact]
public async Task IndexUsers()
{
connectionString = configuration.GetValue<string>("DBInfo:ConnectionString");
var aCon = new AccountController(configuration);
var uCon = new UserController(configuration);
LoginModel model = new LoginModel
{
Login = "postgres",
Password = "111"
};
aCon.Authorization(model);
var result = uCon.Index();
var okResult = result.Should().BeOfType<OkObjectResult>().Subject;
var persons = okResult.Value.Should().BeAssignableTo<IEnumerable<Documents>>().Subject;
persons.Count().Should().Be(7);
}
}
}
测试显示我的错误
var result = uCon.Index();
让我得到NullReferenceException。
我如何解决这个问题?
答案 0 :(得分:2)
首先,您不是单元测试,而是集成测试。一旦你在混合中得到类似数据库连接的东西,单元测试就完全可以了。如果您的目标是为存储库类编写单元测试,那么您应该模拟数据存储。
其次,你不应该注入IConfiguration,如果你需要配置中的一些数据,比如连接字符串,你应该将它绑定到一个强类型的类,然后注入它:
services.Configure<MyConnectionStringsClass>(Configuration.GetSection("ConnectionStrings"));
然后,注入IOptionsSnapshot<MyConnectionStringsClass>
。
第三,无论如何,你真的不应该这样处理它。如果您的存储库依赖于IDbConnection
,那么您应该将注入到您的存储库中。在Startup.cs中:
services.AddScoped(p => new NpgsqlConnection(Configuration.GetConnectionString("Foo"));
然后,在您的repo构造函数中接受NpgsqlConnection
并将其设置为私有字段。
第四,如果你坚持继续你现在的方式,你绝对不应该在你的Connection
财产上有新闻NpgsqlConnection
。这意味着每次访问此属性时都会获得一个新实例。相反,您应该将其定义为简单{ get; private set; }
,并将其设置在repo的构造函数中。
第五,您不应该将using
与以任何一种方式定义的属性一起使用,因为它将在您第一次执行后处理,使所有后续查询失败并显示ObjectDisposedException
。如果您要在课堂上重新修改,那么您的课程需要实施IDisposable
,您应该使用Dispose
方法处理您的连接。 FWIW,如果你将所有依赖项(包括你的连接)注入你的类,你不需要实现IDisposable
,因为它不需要处理所需的类 - 使用依赖注入的另一个重要原因顺便说一下。
最后,为了回答您的主要问题,您应该使用TestServer
。在创建TestServer
时,您将Startup
类作为类型参数传递给您,因此您最终会获得实际应用的真实副本,以及所有相应的服务等。然后,您可以发出HTTP请求,就像使用HttpClient
来测试控制器操作等。但是,这仅适用于集成测试,这是唯一一次真正拥有PostreSQL数据库的方法。