Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 我必须对使用连接字符串的方法进行单元测试。是否可以使用实体框架来帮助我测试连接_C#_Entity Framework_Unit Testing - Fatal编程技术网

C# 我必须对使用连接字符串的方法进行单元测试。是否可以使用实体框架来帮助我测试连接

C# 我必须对使用连接字符串的方法进行单元测试。是否可以使用实体框架来帮助我测试连接,c#,entity-framework,unit-testing,C#,Entity Framework,Unit Testing,我必须为此做一个单元测试,这让我发疯,因为我不知道在没有连接到数据库的情况下应该如何做。这不是我自己编写的代码,而是我团队中的一员编写的代码 公共IActionResult家庭医生 { 列出GetPatientData { List PatientDataArray=新列表; 连接连接=新连接; MySqlConnection=null; 尝试 { connection=new MySqlConnectionconn.getConnectionString; 连接。打开; MySqlComman

我必须为此做一个单元测试,这让我发疯,因为我不知道在没有连接到数据库的情况下应该如何做。这不是我自己编写的代码,而是我团队中的一员编写的代码

公共IActionResult家庭医生 { 列出GetPatientData { List PatientDataArray=新列表; 连接连接=新连接; MySqlConnection=null; 尝试 { connection=new MySqlConnectionconn.getConnectionString; 连接。打开; MySqlCommand cmd=新的MySqlCommand; cmd.Connection=连接; cmd.CommandText=从测量中选择*;; cmd.准备; MySqlDataReader=cmd.ExecuteReader; 边读边读 { int ID=reader.GetInt32id; DecimalBloodugar=reader.getDecimalBloodugar; decimal BloodugardSired=reader.getDecimalBloodugardSired; 字符串描述=reader.GetStringdescription; DateTime=reader.GetDateTimetime; //int status=reader.GetInt16status; PatientDataArray.Addnew PatientID,Bloodugar,Bloodugardesired,description,time; } } 最后 { 如果连接!=null 连接。关闭; } 返回PatientDataArray; } ViewData[患者]=获取患者数据; 返回视图; } }
这样的代码不能进行单元测试,只能使用已知的数据状态进行集成测试。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;
}
正如您可能知道的,这对测试来说有些毫无意义,但是视图在没有数据库的情况下是可以测试的,因为PatientPository可以被模拟并设置为返回已知的数据状态,或者抛出异常等,而不需要数据库连接。如果控制器正在检查或转换患者数据,则可以基于已知状态测试该逻辑。您不需要对存储库代码进行单元测试,它只是获取数据。您需要单元测试行为,在这种情况下,实际上没有行为

这有助于使代码能够进行测试,但无论是否使用存储库,它都不是特别有效。您的数据访问方法是从数据库中选择*以填充模型。实体框架和工作单元模式有助于提高效率,同时仍然易于测试

例如,定义一个实体以反映系统中的完整度量和相关记录。使用repository模式,您可以返回您的实体的IQueryable,测试中的调用代码可以使用这些实体

控制器定义了作为DbContext容器的工作单元。把DbContext想象成连接

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();
}
这将仅返回活动患者的活动测量值。对于更多特定于场景的条件,您可以向调用添加方法或参数,以使存储库应用额外的筛选,但我更愿意让使用者根据需要应用特定的条件。它使存储库更加简单、轻量级,并且更易于模拟

这给了我们什么

通过返回IQueryable,我们允许存储库的使用者选择他们想要的数据,或者他们想要对这些数据做什么。在上述情况下,通过只选择5个字段,执行的SQL将只选择这5列,而不是选择*。我们应用的任何条件都将转换为SQL,从而加快查询速度。如果我们只需要一个计数,或者一个带有Any的exists检查,那么这些查询将比选择所有数据来检查这些查询的性能要好得多

与我们的测试夹具c一样,代码对于单元测试要简单得多 构建IUnitOfWorkFactory和存储库的模拟,其中存储库模拟只返回一个列表或一个组成的患者对象数组,作为.AsQueryable供逻辑使用

同样,如果您只想从数据库中获取一组数据并将其输出到一个视图,那么单元测试并不能真正获得任何值。它只是什么都不做。但是,如果您的代码希望执行一个操作,其中它将检索数据,并决定执行什么操作,或者是否基于返回的数据执行某些操作,请重新分解代码以从该业务逻辑中断数据检索,利用EF高效地查询这些数据将变得更加有用和易于测试

下一件事是看看如何返回数据。单元测试非常适合通过检查返回值和断言模拟来断言行为的结果。使用ASP.Net特定的结构(如ViewData)很难进行测试。返回ViewModels会更容易一些。一般来说,我建议在视图方法不采用填充模型的情况下,设计异步加载数据的页面,并使用返回JSon作为ActionResult的GET调用呈现为空并启动数据加载,或者移交给返回适用数据集合的服务,其中控制器仅包装该数据。在最后一种情况下,单元测试的是服务,而不是控制器


因此,考虑到这一点,您可以对现有代码进行单元测试吗?不,不是真的。但是这应该给你一些弹药,让你回到团队的其他成员那里,说如果他们想让代码被单元测试覆盖,这就是他们应该应用的一种重新分解来实现它。单元测试是必须预先考虑的事情。如果项目没有使用IoC/DI这样的测试友好模式,那么在开发过程的后期很难引入这种模式。

这样的代码不能进行单元测试,只能使用已知的数据状态进行集成测试。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;
}
正如您可能知道的,这对测试来说有些毫无意义,但是视图在没有数据库的情况下是可以测试的,因为PatientPository可以被模拟并设置为返回已知的数据状态,或者抛出异常等,而不需要数据库连接。如果控制器正在检查或转换患者数据,则可以基于已知状态测试该逻辑。您不需要对存储库代码进行单元测试,它只是获取数据。您需要单元测试行为,在这种情况下,实际上没有行为

这有助于使代码能够进行测试,但无论是否使用存储库,它都不是特别有效。您的数据访问方法是从数据库中选择*以填充模型。实体框架和工作单元模式有助于提高效率,同时仍然易于测试

例如,定义一个实体以反映系统中的完整度量和相关记录。使用repository模式,您可以返回您的实体的IQueryable,测试中的调用代码可以使用这些实体

控制器定义了作为DbContext容器的工作单元。把DbContext想象成连接

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();
}
这将仅返回活动患者的活动测量值。对于更多特定于场景的条件,您可以向调用添加方法或参数,以使存储库应用额外的筛选,但我更愿意让使用者根据需要应用特定的条件。它使存储库更加简单、轻量级,并且更易于模拟

这给了我们什么

通过返回IQueryable,我们允许存储库的使用者选择他们想要的数据,或者他们想要对这些数据做什么。在上述情况下,通过只选择5个字段,执行的SQL将只选择这5列,而不是选择*。任何W 在这里,我们应用的条件将转换为SQL,从而加快查询速度。如果我们只需要一个计数,或者一个带有Any的exists检查,那么这些查询将比选择所有数据来检查这些查询的性能要好得多

对于单元测试来说,代码要简单得多,因为我们的测试夹具可以构建IUnitOfWorkFactory和存储库的模拟,其中存储库模拟只是返回一个列表或一个组成的患者对象数组,作为可供逻辑使用的.asquery

同样,如果您只想从数据库中获取一组数据并将其输出到一个视图,那么单元测试并不能真正获得任何值。它只是什么都不做。但是,如果您的代码希望执行一个操作,其中它将检索数据,并决定执行什么操作,或者是否基于返回的数据执行某些操作,请重新分解代码以从该业务逻辑中断数据检索,利用EF高效地查询这些数据将变得更加有用和易于测试

下一件事是看看如何返回数据。单元测试非常适合通过检查返回值和断言模拟来断言行为的结果。使用ASP.Net特定的结构(如ViewData)很难进行测试。返回ViewModels会更容易一些。一般来说,我建议在视图方法不采用填充模型的情况下,设计异步加载数据的页面,并使用返回JSon作为ActionResult的GET调用呈现为空并启动数据加载,或者移交给返回适用数据集合的服务,其中控制器仅包装该数据。在最后一种情况下,单元测试的是服务,而不是控制器


因此,考虑到这一点,您可以对现有代码进行单元测试吗?不,不是真的。但是这应该给你一些弹药,让你回到团队的其他成员那里,说如果他们想让代码被单元测试覆盖,这就是他们应该应用的一种重新分解来实现它。单元测试是必须预先考虑的事情。如果项目没有使用IoC/DI等测试友好模式,那么在开发过程的后期很难引入。

您无法进行连接到数据库的单元测试。不过,您可以进行集成测试。您应该测试方法的哪一部分?哦,您可能想向另一个团队成员提到,应该处理命令和数据读取器对象以及连接,并且使用语句是执行此操作的常用方法。当您这样做时,建议他们不要使用SELECT*FROM,而是在SELECT语句中引用他们想要的列。显示的代码看起来与实体框架无关。这段代码应该被重构以使用数据抽象,也不应该与连接实现紧密耦合。然后让他们拿起一本关于软件开发的现代书籍,或者交换团队……你不能进行连接到数据库的单元测试。不过,您可以进行集成测试。您应该测试方法的哪一部分?哦,您可能想向另一个团队成员提到,应该处理命令和数据读取器对象以及连接,并且使用语句是执行此操作的常用方法。当您这样做时,建议他们不要使用SELECT*FROM,而是在SELECT语句中引用他们想要的列。显示的代码看起来与实体框架无关。这段代码应该被重构以使用数据抽象,也不应该与连接实现紧密耦合,然后让他们拿起一本关于软件开发的现代书籍,或者交换团队。。。