我有以下方法:
Void UpdateUser(User user){}
我需要检查这个方法是否能正常工作。
我在单元测试中使用了一个单独的数据库来检查这一点。但是很多有经验的人说如果我用这种方法就不是单元测试了;那是集成测试。
但我不知道如何模拟单元测试。
该UpdateUser
方法中编写的代码将尝试使用实体框架更新数据。
如果我模拟(实际上我也不怎么做),这将如何与实体框架一起工作?
我有以下方法:
Void UpdateUser(User user){}
我需要检查这个方法是否能正常工作。
我在单元测试中使用了一个单独的数据库来检查这一点。但是很多有经验的人说如果我用这种方法就不是单元测试了;那是集成测试。
但我不知道如何模拟单元测试。
该UpdateUser
方法中编写的代码将尝试使用实体框架更新数据。
如果我模拟(实际上我也不怎么做),这将如何与实体框架一起工作?
模拟意味着您开发软件组件(类)的方式是,任何具有行为的类都作为接口(或抽象类)使用/使用/调用。您对抽象进行编程。运行时您使用某些东西(服务定位器、DI 容器、工厂等)来检索/创建这些实例。
最常见的方式是使用构造注入。这是对为什么要使用 DI 的一个很好的解释,以及如何做到这一点的示例。
在您的情况下,使用实体框架的组件(例如您的存储库)必须实现存储库接口,并且使用您的存储库的任何类都应将其用作接口。
这样,您可以在单元测试中模拟存储库。这意味着您创建一个单元测试存储库类(与任何数据库或 EF 无关),并在您创建要进行单元测试的类的实例时使用它。
您可以使用事务和回滚或创建一个测试用户尝试其更新。断言,然后在 finally 块中删除测试用户。
您可以使用 moq、rhino 等模拟框架。moq 非常简单,您可以找到许多使用 DI 演示 moq 的示例,例如统一框架。
如果你的课是这样的
public class UserRepository()
{
Sqlcontext _context;
void UpdateUser(User user)
{
_context.Users.Add(user);
}
}
那么这不是可单元测试的。
虽然这不是单元测试,但如果您坚持连接数据库并对其进行测试,您可以将您的功能更改为
User UpdateUser(User user)
{
_context.Users.Add(user);
return user;
}
并测试是否
user.Id > 0
在这里,您基本上只是在测试实体框架。
“我在单元测试中使用了一个单独的数据库来检查这一点。但是许多有经验的人说,如果我使用这种方法,那将不是单元测试;那是集成测试。”
那些人是错误的,尽管他们应该有经验。出于某种原因,单元测试都是关于孤立地测试部分代码的错误观念近年来越来越流行。实际上,单元测试就是编写作为一个单元的测试,换句话说,它们是孤立存在的,一个单元测试的结果不能影响另一个测试。
如果你的UpdateUser
方法直接访问 EF,那么只要你保证在每次测试结束时保证数据库回滚到它的起始状态,那么你就有了单元测试。但是,为每个测试设置数据库并确保它可以可靠地回滚可能需要做很多工作。这就是为什么经常使用模拟。其他答案已经涵盖了 mcoking EF,所以我不会讨论这个问题。
为了大大简化您的测试,您可以在UpdateUser
EF 和 EF 之间设置一个外推层。换句话说,UpdateUser
该类被提供了一个接口的实例,这是它进入 EF 的网关。它不直接与 EF 对话。然后要模拟 EF,您只需提供接口的模拟实现。然后,这将针对 EF 进行测试的需求推向了更基本的层,具有更基本的类似 CRUD 的行为。
一个非官方的技巧,不是最佳实践可以是在测试时使用内存数据库(上下文)。
在测试结束时使用事务并回滚您的事务