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# 使用实体框架对webapi进行单元测试_C#_Entity Framework_Unit Testing - Fatal编程技术网

C# 使用实体框架对webapi进行单元测试

C# 使用实体框架对webapi进行单元测试,c#,entity-framework,unit-testing,C#,Entity Framework,Unit Testing,关于使用实体框架的单元测试项目,还有比这更好的例子或教程吗 在我的例子中,API项目使用实体框架文件Edmx文件,并从存储库类的Edmx文件访问表。[与codefirst或dbfirst方法不同] repo类的结构如下所示 public class AppBackendRepository { // modify the type of the db field private AppDBEntities db_context = new AppDBEntities();

关于使用实体框架的单元测试项目,还有比这更好的例子或教程吗

在我的例子中,API项目使用实体框架文件Edmx文件,并从存储库类的Edmx文件访问表。[与codefirst或dbfirst方法不同]

repo类的结构如下所示

 public class AppBackendRepository
{
    // modify the type of the db field
    private AppDBEntities db_context = new AppDBEntities();

    public List<Student> Get()
    {
        return db_context.Students.ToList();
    }
}



public class StudentController
{

    private static AppBackendRepository repo;
    public  StudentController()
    {

        repo = new AppBackendRepository();
    }

    public  IEnumerable<Student> GetStudents()
    {
        List<Student> students = repo.Get();

        return students;
    }
}
公共类AppBackendRepository
{
//修改db字段的类型
私有AppDBEntities db_context=新AppDBEntities();
公共列表Get()
{
返回db_context.Students.ToList();
}
}
公共班级学生控制员
{
私有静态AppBackendRepository回购;
公共学生控制员()
{
repo=新建AppBackendRepository();
}
公共IEnumerable GetStudents()
{
List students=repo.Get();
留学生;
}
}

如何针对这种代码体系结构编写适当的单元测试?快速的答案是:你没有。 现在,我这么说是因为我倾向于认为“单元测试”是快速的,可以用于持续集成,而“集成测试”是缓慢的测试,只在晚上运行,当然,当您使用它们时

您在这里创建的问题是您正在使用不稳定的代码

以您的方法“GetStudents()”为例。在调用此方法之前,您需要依赖于实际存在的回购协议。任何单元测试都将取决于安装的实体框架,当然,这将非常缓慢。想象一下有几百个这样的单元测试框架,你的单元测试框架现在在你的系统中成了一个严重的障碍,让人们说“它太慢了,我们不使用它”

一个更好的方法是实施

首先,定义一个接口:

public interface IStudentRepository
{
    IEnumerable<Student> GetStudents();
}
公共接口是一个默认的接口
{
IEnumerable GetStudents();
}
现在,您的类只是该契约的一个实现细节,例如:

public class StudentRepository : DbContext, IStudentRepository
{
    private DbSet<Student> Students;

    public IEnumerable<Student> GetStudents()
    {
        return Students;
    }
}
public class StudentRepository:DbContext,IStudentRepository
{
私立DbSet学生;
公共IEnumerable GetStudents()
{
留学生;
}
}
在使用存储库的类中,您现在可以通过构造函数注入来注入实例,并最终得到完全可单元测试的内容:

public class StudentEnrollment
{
    private readonly IStudentRepository _studentRepository;

    // Inject the contract here
    public StudentEnrollment(IStudentRepository studentRepository)
    {
        _studentRepository = studentRepository;
    }


    public IEnumerable<Student> GetStudentsForClass(StudentClass studentClass)
    {
        return _studentRepository.GetStudents().Where(student => student.class == studentClass);
    }
}
公共班级学生集合
{
私人只读是学生档案库(studentRepository);
//在这里插入合同
公共学生集合(ISTUDENTREPOSITION STUDENTREPOSITION)
{
_studentRepository=studentRepository;
}
公共IEnumerable GetStudentsForClass(StudentClass StudentClass)
{
返回_studentRepository.GetStudents(),其中(student=>student.class==studentClass);
}
}
现在,作为额外的好处,您可以对逻辑的每一个细节进行单元测试,例如:

[TestMethod]
public void GetStudentsForClass_GetStudentsThrowsException_ResultIsNull()
{
    // Arrange
    var mock = Mock.Create<IStudentRepository();
    var badException = new Exception("I'm bad");
    mock.Setup(repo => repo.GetStudents()).Throws(badException);
    var someClass = new StudentClass();
    var instance = new StudentEnrollment(mock.object);

    // Act
    var result = instance.GetStudentsForClass(studentClass);

    // Assert
    result.ShouldBeEmpty();
}
[TestMethod]
public void GetStudentsForClass\u GetStudentsSthrowsException\u ResultIsNull()
{
//安排
var mock=mock.Create repo.GetStudents()).Throws(badException);
var someClass=newstudentclass();
var实例=新StudentEnrollment(mock.object);
//表演
var result=instance.GetStudentsForClass(studentClass);
//断言
result.ShouldBeEmpty();
}

快速回答是:你没有。 现在,我这么说是因为我倾向于认为“单元测试”是快速的,可以用于持续集成,而“集成测试”是缓慢的测试,只在晚上运行,当然,当您使用它们时

您在这里创建的问题是您正在使用不稳定的代码

以您的方法“GetStudents()”为例。在调用此方法之前,您需要依赖于实际存在的回购协议。任何单元测试都将取决于安装的实体框架,当然,这将非常缓慢。想象一下有几百个这样的单元测试框架,你的单元测试框架现在在你的系统中成了一个严重的障碍,让人们说“它太慢了,我们不使用它”

一个更好的方法是实施

首先,定义一个接口:

public interface IStudentRepository
{
    IEnumerable<Student> GetStudents();
}
公共接口是一个默认的接口
{
IEnumerable GetStudents();
}
现在,您的类只是该契约的一个实现细节,例如:

public class StudentRepository : DbContext, IStudentRepository
{
    private DbSet<Student> Students;

    public IEnumerable<Student> GetStudents()
    {
        return Students;
    }
}
public class StudentRepository:DbContext,IStudentRepository
{
私立DbSet学生;
公共IEnumerable GetStudents()
{
留学生;
}
}
在使用存储库的类中,您现在可以通过构造函数注入来注入实例,并最终得到完全可单元测试的内容:

public class StudentEnrollment
{
    private readonly IStudentRepository _studentRepository;

    // Inject the contract here
    public StudentEnrollment(IStudentRepository studentRepository)
    {
        _studentRepository = studentRepository;
    }


    public IEnumerable<Student> GetStudentsForClass(StudentClass studentClass)
    {
        return _studentRepository.GetStudents().Where(student => student.class == studentClass);
    }
}
公共班级学生集合
{
私人只读是学生档案库(studentRepository);
//在这里插入合同
公共学生集合(ISTUDENTREPOSITION STUDENTREPOSITION)
{
_studentRepository=studentRepository;
}
公共IEnumerable GetStudentsForClass(StudentClass StudentClass)
{
返回_studentRepository.GetStudents(),其中(student=>student.class==studentClass);
}
}
现在,作为额外的好处,您可以对逻辑的每一个细节进行单元测试,例如:

[TestMethod]
public void GetStudentsForClass_GetStudentsThrowsException_ResultIsNull()
{
    // Arrange
    var mock = Mock.Create<IStudentRepository();
    var badException = new Exception("I'm bad");
    mock.Setup(repo => repo.GetStudents()).Throws(badException);
    var someClass = new StudentClass();
    var instance = new StudentEnrollment(mock.object);

    // Act
    var result = instance.GetStudentsForClass(studentClass);

    // Assert
    result.ShouldBeEmpty();
}
[TestMethod]
public void GetStudentsForClass\u GetStudentsSthrowsException\u ResultIsNull()
{
//安排
var mock=mock.Create repo.GetStudents()).Throws(badException);
var someClass=newstudentclass();
var实例=新StudentEnrollment(mock.object);
//表演
var result=instance.GetStudentsForClass(studentClass);
//断言
result.ShouldBeEmpty();
}

我认为您的所有代码都应该经过测试。通过这种方式,您可以很容易地检测到某些开发人员何时打破了预期的链。因此,我总是为存储库和控制器添加测试。在您的情况下,我将添加一个测试,确保您的控制器以正确的方式使用存储库,并且存储库以正确的方式使用EF。但是,您不应该测试EF本身。Th
public class AppBackendRepository
{
    private IDbContext _dbContext;

    // With injection.
    public AppBackendRepository(IDbContext context)
    {
        _dbContext = context;
    }

    public List<Student> Get()
    {
        // Only active...
        return _dbContext.Students.Where(x => x.Active).ToList();
    }
}
public class StudentController
{
    private static IAppBackendRepository _repo;
    public  StudentController(IAppBackendRepository repo)
    {
        _repo = repo;
    }

    public  IEnumerable<Student> GetStudents()
    {
        List<Student> students = _repo.Get();
        return students;
    }
}

[TestMethod]
public void ShouldCallRepo()
{
    // With Rhino
    var mockRepo = MockRepository.GenerateStub<IAppBackendRepository>();
    var expectedResult = new List<Student>();
    mockRepo.Expect(x => x.Get()).Return(expectedResult);
    var controller = new StudentController(mockRepo);
    var actualResult = controller.GetStudents();
    mockRepo.VerifyAllExpectations();
    Assert.AreEqual(actualResult, expectedResult); // Possible in it's own method.
}