目录
介绍
示例场景
实体框架
单元测试
类图
基于用户接口的测试架构
自动化测试架构
单元测试的哲学
演练:使用Visual Studio单元测试框架运行测试方法
介绍在业务应用程序中进行编码时,我们都熟悉一种非常常见的场景。实际上,这是我们想要将对象保存到数据库的最常见场景。但是我们怎么知道我们的代码运行正常呢?好吧,我们有很多方法可以知道。有些是很好的方法,有些则不是。我们来讨论使用场景。
示例场景假设我们要保存一个Student对象所在类中有Name,Phone,Email和Id。要保存此对象,我们应该创建一个名为StudentRepository的存储库类。在这个类中,我们将编写数据保存代码。
现在我想提一些观点。最好为每个存储库类创建一个接口。它是Repository Pattern的子集。
在我们的例子中,我们应该创建IStudentRepository接口,其中我们将仅定义Save方法,同时创建StudentRepository类实现此接口。
总而言之,我们有三个项目。分别是DataAccess,DataAccess.Contract,并且Domain取决于这中状态。以下是类定义和项目架构。
为了实现数据库访问代码,我们不会使用传统的SqlClient库类,也不会编写传统的SQL查询。相反,我们将使用实体框架。实体框架(EF)是一种对象关系映射器,它使.NET开发人员能够使用特定于域的对象处理关系数据。它消除了开发人员通常需要编写的大多数数据访问代码的问题。
要在我们的项目中使用该框架,我们需要安装它。但是我们在哪里找到那个库?好。Microsoft开发了一个扩展,通过该扩展,我们可以非常简单地将外部库安装、更新和卸载到我们的项目中。以下是我们如何将Entity Framework安装到我们的DataAccess项目中。
演练:使用Nuget安装实体框架
- 右键单击DataAccess项目的引用选项。
- 找到Entity Framework项目(下图中的第二个)。
- 单击该项目的“安装”按钮。
- 当系统要求您提供许可协议时,请单击“接受”。
- 安装成功后,您应该看到绿色标志而不是“安装”按钮。
在安装实体框架之后,我们应该创建一个类DataContext,它将继承DBContext类,并且我们将使用OnModelCreating方法下的表名映射我们的Student类。当第一次调用DataContext类时,实体框架将查找数据库并自行创建数据库(如果该数据库不存在)。接下来,它将根据我们在OnModelCreating方法中给出的指令创建表。从下面的类中,系统将创建一个在.\SQLEXPRESS服务器中命名为MockingPractices.DataAccess.DataContext的数据库(因为我们没有给出任何连接字符串,它将在默认服务器中执行)。而且,Student表已创建。
数据库
DataContext类
namespace MockingPractices.DataAccess
{
using System.Data.Entity;
using MockingPractices.Domain;
public class DataContext:DbContext
{
public DbSet Students { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity().ToTable("Student");
base.OnModelCreating(modelBuilder);
}
}
}
IStudentRepository接口
namespace MockingPractices.DataAccess.Contract
{
using MockingPractices.Domain;
public interface IStudentRepository
{
int Save(Student student);
}
}
StudentRepository类
namespace MockingPractices.DataAccess
{
using MockingPractices.DataAccess.Contract;
using MockingPractices.Domain;
public class StudentRepository : IStudentRepository
{
public int Save(Student student)
{
using (var context=new DataContext())
{
Student studentAdded = context.Students.Add(student);
context.SaveChanges();
return studentAdded.Id;
}
}
}
}
单元测试
现在我们将找到一种测试代码的方法。按照传统方式,我们必须创建一个简单的用户界面(可能是Windows窗体应用程序),其中会有一个按钮。如果我们单击该按钮,我们将创建一个student对象并将其传递给存储库方法。以下是场景。
类图但是如果我们经常更改我们的代码并需要测试,那么每次我们必须运行UI并按下按钮进行测试。如果我们需要针对单个存储库save方法测试多个场景,情况会变得更糟。因此,我们可以理解的是,我们需要一个能够自动管理这些方法调用的系统。对于开发代码的每次更改,我们无需一次次单击用户界面。以下可能是建议的架构之一。
自动化测试架构这种类型的测试被称为自动化单元测试,目前,有几个框架用于此目的。NUnit和Visual Studio的内部单元测试框架都很常见。让我们在我们的解决方案中使用第二个。以下是如何为您的解决方案创建单元测试项目。如果你仍然不明白,不要担心。请继续阅读以下内容。
转到:添加新项目 -> Visual C# ->测试 ->单元测试项目
提供适当的名称,然后按OK按钮。
每个单元测试框架都有一些类,编译器可以通过这些类来了解应该运行哪些类。此标记是用于此的TestClass,并且所需的测试方法必须在其上具有TestMethod标记。
在我们的例子中,我们可以将默认类重命名为StudentRepositoryTest类,并将给定的模板方法重命名为SaveShouldReturnSavedId方法。
所以,测试方法现在如下所示:
让我们从一个非常悲伤但真实的场景开始。假设有一天你处于一个浪漫的模式,想和你的爱人交谈并且说“我爱你Jaan”。你期望听到什么?我们都期望“亲爱的我也爱你”或类似的回复。但如果你的爱人对你大喊大叫,那么这种喊叫绝对不会与你的期望相符。我说的对吗?
在编程世界中,我们希望我们的方法能够顺利地工作而没有任何问题。我们确切地知道对特定方法的期望。在我们的场景中,我们希望我们的存储库方法保存student对象并返回该对象的已保存的ID。而且我们也知道Id不能为零,因为我们的数据库的主键是一个自动递增的数字,并且没有办法将对象保存在id= 0的行中。所以,我们的期望是返回值不应该等于零。对吗?说得通吗?
那么我们如何在代码中实现这种情况呢?
有一个名为Assert的类,由Microsoft 生成。其职责是将预期值与返回/实际值相匹配。如果期望与实际匹配,则显示绿色,但如果期望不匹配,则显示红色。所以代码如下所示:
namespace MockingPractices.DataAccess.Test
{
using System.Transactions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MockingPractices.DataAccess.Contract;
using MockingPractices.Domain;
[TestClass]
public class StudentRepositoryTest
{
[TestMethod]
public void SaveShouldReturnSavedId()
{
using (TransactionScope scope = new TransactionScope())
{
IStudentRepository studentRepository = new StudentRepository();
Student student = new Student()
{
Id = 0,
Name = "test name",
Email = "testemail@email.com",
Phone = "123456"
};
int id = studentRepository.Save(student);
Assert.AreNotEqual(0, id);
}
}
}
}
现在,如果我们按照下面的图像,我们可以指示系统运行测试方法并执行该方法中的代码。
演练:使用Visual Studio单元测试框架运行测试方法- 将光标移动到下图中给出的图标。
- 单击它,然后按运行。
- 将出现一个窗口,指示正在运行的测试的状态。
- 如果测试成功运行,则应显示以下图像。
如果您严格遵循我的上述说明,您现在应该看到下面给出的绿色标志。因此,我们可以使用单元测试来测试我们的数据库代码,而无需任何类型的用户界面。
但是上述工作存在一些问题。
- 我们不应该将测试数据保留在数据库中
- 我们不应该由我们创造帮助对象。以下是我们解决这些问题的方法。
主要规则是我们必须在test方法之后恢复数据库insert操作。我们可以使用TransactionScope类。
其次,我们应该使用一个框架来创建那些帮助存根。我们将使用NBuilder为我们构建对象。NBuilder可以使用Nuget完成安装。
您应该看到项目中已安装的软件包,请转到下图:
因此,在编码解决这些问题后,我们的代码应如下所示:
namespace MockingPractices.DataAccess.Test
{
using System.Transactions;
using FizzWare.NBuilder;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MockingPractices.DataAccess.Contract;
using MockingPractices.Domain;
[TestClass]
public class StudentRepositoryTest
{
[TestMethod]
public void SaveShouldReturnSavedId()
{
using (TransactionScope scope = new TransactionScope())
{
IStudentRepository studentRepository = new StudentRepository();
Student student = Builder.CreateNew().With(s => s.Id = 0).Build();
int id = studentRepository.Save(student);
Assert.AreNotEqual(0, id);
}
}
}
}
只需按Run命令即可运行尽可能多的测试。您永远不需要反复打开用户界面并输入值并自行计算预期值。这是单元测试的真正美的地方。
原文地址:https://www.codeproject.com/Articles/488264/Integration-Testing-Made-Easy-Part-1-Repository-Te