gpt4 book ai didi

c# - 我必须对使用连接字符串的方法进行单元测试。是否可以使用 Entity Framework 来帮助我测试连接

转载 作者:太空宇宙 更新时间:2023-11-03 22:29:42 24 4
gpt4 key购买 nike

我必须为此进行单元测试,这使我发疯,因为我不知道如何在不连接数据库的情况下执行此操作。这不是我自己编写的代码,而是代码组成的小组的成员。

public IActionResult FamilyDoctor()
{
List<Patient> GetPatientData()
{
List<Patient> PatientDataArray = new List<Patient>();

Connection conn = new Connection();
MySqlConnection connection = null;
try
{
connection = new MySqlConnection(conn.getConnectionString());
connection.Open();
MySqlCommand cmd = new MySqlCommand();
cmd.Connection = connection;
cmd.CommandText = "SELECT * FROM measurement;";
cmd.Prepare();

MySqlDataReader reader = cmd.ExecuteReader();

while (reader.Read())
{

int ID = reader.GetInt32("id");
decimal bloodsugar = reader.GetDecimal("bloodsugar");
decimal bloodsugardesired = reader.GetDecimal("bloodsugardesired");
string description = reader.GetString("description");
DateTime time = reader.GetDateTime("time");
//int status = reader.GetInt16("status");

PatientDataArray.Add(new Patient(ID, bloodsugar, bloodsugardesired, description, time));

}

}
finally
{
if (connection != null)
connection.Close();
}

return PatientDataArray;
}

ViewData["Patient"] = GetPatientData();

return View();
}
}

最佳答案

不能对此类代码进行单元测试,只能对已知数据状态进行集成测试。 EF不会帮助您。要编写可单元测试的代码,您需要开始执行关注点分离和控制反转。例如,存储库模式可以通过包装数据检索来提供帮助,以便业务逻辑可以接收对存储库的依赖关系,单元测试可以模拟该依赖关系。该存储库是使用EF还是ADO与要测试的代码无关。

也就是说,您发布的上述代码没有任何业务逻辑,只是从数据库返回所有患者数据。单元测试旨在测试业务逻辑,该逻辑将基于检索到的数据执行某些操作。但是,可以用最基本的示例代替上面的代码:

public class PatientRepository : IPatientRepository
{
public IEnumerable<Patient> GetAllPatients()
{
List<Patient> PatientDataArray = new List<Patient>();

Connection conn = new Connection();
MySqlConnection connection = null;
try
{
connection = new MySqlConnection(conn.getConnectionString());
connection.Open();
MySqlCommand cmd = new MySqlCommand();
cmd.Connection = connection;
cmd.CommandText = "SELECT * FROM measurement;";
cmd.Prepare();

MySqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
int ID = reader.GetInt32("id");
decimal bloodsugar = reader.GetDecimal("bloodsugar");
decimal bloodsugardesired = reader.GetDecimal("bloodsugardesired");
string description = reader.GetString("description");
DateTime time = reader.GetDateTime("time");

PatientDataArray.Add(new Patient(ID, bloodsugar, bloodsugardesired, description, time));
}
}
finally
{
if (connection != null)
connection.Close();
}

return PatientDataArray;
}


然后在控制器中:

public PatientController(IPatientRepository patientRepository)
{
this.PatientRepository = patientRepository;
}

public IActionResult FamilyDoctor()
{
ViewData["Patient"] = PatientRepository.GetAllPatients();
return View();
}


您可能会说,这有点没有意义,但是视图无需数据库即可进行测试,因为可以模拟PatientRepository并将其设置为返回已知数据状态或引发异常等,而无需数据库连接。如果控制器正在检查或转换患者数据,则可以根据已知状态测试该逻辑。您无需对存储库代码进行单元测试,它只是在获取数据。您对测试行为进行单元测试,在这种情况下,实际上没有行为。

这可以帮助使代码可测试,但是无论有没有存储库,它的效率都不高。您的数据访问方法正在数据库中执行 SELECT *来填充模型。实体框架和工作单元模式可以帮助使其效率更高,同时仍然易于测试。

例如,您定义一个实体以反映完整的Measurement以及系统中的相关记录。使用存储库模式,返回实体的 IQueryable,被测调用代码可以使用这些实体。

控制器定义了作为DbContext容器的工作单元。 (想像DbContext这样的Connection)

public PatientController(IUnitOfWorkFactory unitOfWorkFactory, IPatientRepository patientRepository)
{
this.UnitOfWorkFactory = unitOfWorkFactory;
this.PatientRepository = patientRepository;
}

public IActionResult FamilyDoctor()
{
using(var unitOfWork = UnitOfWorkFactory.Create())
{
var measurements = PatientRepository.GetAllMeasurements(unitOfWork);
var viewModels = measurements.Select(x => new MeasurementViewModel
{
ID = x.Id,
BloodSugar = x.BloodSugar,
BloodSugarDesired = x.BloodSugarDesired,
Description = x.Description,
Time = x.Time
}).ToList();

ViewData["Patient"] = viewModels;
return View();
}


现在,上面的工作单位工厂/模式只是一个存根示例。您可以搜索有关在何处/如何实现工作单元模式的各种示例。 UoW的目的是包装DbContext。它用作EF的DBContext的外观,可以更轻松地用模拟代替来进行测试。

使用EF的度量存储库看起来更像:

public IQueryable<Measurement> GetAllMeasurements(IUnitOfWork unitOfWork)
{
return unitOfWork.Context.Measurements.AsQueryable();
}


注意:如果只想返回整个 AsQueryable()IQueryable,则需要 DbSet。在 Where条件下应用的所有过滤都会自动返回 IQueryable。在许多情况下,您将对数据使用低级规则,例如可能是IsActive状态,以反映活动的,未删除/隐藏的患者的测量结果。存储库可以强制执行这些基本级别的规则,因此您无需记住到处检查它们:

public IQueryable<Patient> GetAllPatients(IUnitOfWork unitOfWork)
{
return unitOfWork.Context.Measurements.Where(x => x.IsActive && x.Patient.IsActive);
}


这将仅返回活跃患者的活跃测量值。对于更多特定于场景的条件,可以在调用中添加方法或参数,以使存储库应用其他过滤,但是我更愿意让使用者根据需要应用特定条件。它使存储库更简单,更轻便,并且更易于模拟。

这给了我们什么?

通过返回 IQueryable<Measurement>,我们允许存储库的使用者选择他们想要的数据,或者他们想要对该数据进行什么处理。在上述情况下,通过仅选择5个字段,执行的SQL将仅选择这5列,而不是 SELECT *。我们应用的所有 Where条件都将转换为SQL,从而加快查询速度。如果我们只想使用 Count或使用 Any进行存在检查,则与选择所有数据进行检查相比,这些查询的查询性能要好得多。

该代码对于单元测试而言要简单得多,因为我们的测试夹具可以构造IUnitOfWorkFactory和Repository的模拟,其中存储库模拟简单地将构成的Patient对象的列表或数组作为 .AsQueryable()返回给逻辑使用。

同样,只想从数据库中获取一组数据并吐出到视图中的情况并不能从单元测试中真正获得任何价值。它根本什么也没做。但是,如果您有想要执行某项操作的代码,该代码将在其中取回数据并根据返回的数据来决定要做什么或是否要做某事,请重构代码以从中进行数据检索业务逻辑,并利用EF来有效地查询该数据将变得更加有用,并且更易于测试。

接下来的事情是看你如何返回数据。单元测试非常适合通过检查返回值和声明模拟来声明行为的结果。使用像 ViewData这样的ASP.Net特定结构很难进行测试。返回 View(viewModels)会容易一些。通常,我建议设计页面以异步加载数据,而“ View”方法不采用填充的模型,而是使用返回 JSon()作为ActionResult的GET调用将其呈现为空并开始数据加载,或者执行到服务,该服务返回适用数据的集合,而控制器仅包装这些数据。在最后一种情况下,您将对服务(而不是控制器)进行单元测试。

因此,考虑到这一点,您可以采用现有代码并对其进行单元测试吗?不,不是。但这应该给您一些弹药,让您回到团队的其他成员那里,并说,如果他们希望单元测试涵盖代码,这是他们应采用的重构方法。单元测试是必须预先容纳的。如果项目未使用IoC / DI等易于测试的模式,则可能很难在开发过程的后期引入。

关于c# - 我必须对使用连接字符串的方法进行单元测试。是否可以使用 Entity Framework 来帮助我测试连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58584386/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com