Joh*_*ner 2 unit-testing entity-framework
关于一件事,我已经读了很多(数十篇文章):
如何对其中包含实体框架代码的业务逻辑代码进行单元测试。
我有3层的WCF服务:
我的业务逻辑将DbContext用于所有数据库操作。现在,我所有的实体都是POCO(以前是ObjectContext,但我对此进行了更改)。
我已阅读拉吉斯拉夫Mrnka的答案在这里,并在这里 的原因,我们应该不假\伪造的DbContext。
他说: “这就是为什么我认为处理上下文/ Linq到实体的代码应该包含集成测试并针对实际数据库进行工作的原因。”
并且: “当然,您的方法在某些情况下有效,但单元测试策略必须在所有情况下均有效-要使其起作用,必须将EF和IQueryable完全从已测试的方法移开。”
我的问题是-您如何实现这一目标???
public class TaskManager
{
public void UpdateTaskStatus(
Guid loggedInUserId,
Guid clientId,
Guid taskId,
Guid chosenOptionId,
Boolean isTaskCompleted,
String notes,
Byte[] rowVersion
)
{
using (TransactionScope ts = new TransactionScope())
{
using (CloseDBEntities entities = new CloseDBEntities())
{
User currentUser = entities.Users.SingleOrDefault(us => us.Id == loggedInUserId);
if (currentUser == null)
throw new Exception("Logged user does not exist in the system.");
// Locate the task that is attached to this client
ClientTaskStatus taskStatus = entities.ClientTaskStatuses.SingleOrDefault(p => p.TaskId == taskId && p.Visit.ClientId == clientId);
if (taskStatus == null)
throw new Exception("Could not find this task for the client in the database.");
if (taskStatus.Visit.CustomerRepId.HasValue == false)
throw new Exception("No customer rep is assigned to the client yet.");
TaskOption option = entities.TaskOptions.SingleOrDefault(op => op.Id == optionId);
if (option == null)
throw new Exception("The chosen option was not found in the database.");
if (taskStatus.RowVersion != rowVersion)
throw new Exception("The task was updated by someone else. Please refresh the information and try again.");
taskStatus.ChosenOptionId = optionId;
taskStatus.IsCompleted = isTaskCompleted;
taskStatus.Notes = notes;
// Save changes to database
entities.SaveChanges();
}
// Complete the transaction scope
ts.Complete();
}
}
}
Run Code Online (Sandbox Code Playgroud)
随附的代码中演示了我的业务逻辑中的功能。该函数具有到数据库的多个“行程”。我不明白,我究竟怎么可以剥夺这个函数的代码EF出一个单独的程序,让我能够单元测试这个功能(通过注入一些假数据而不是EF数据),以及集成测试组装包含“ EF功能”。
拉迪斯拉夫或任何其他人可以帮忙吗?
[编辑]
这是业务逻辑中的另一个代码示例,我不明白如何从测试的方法中“删除EF和IQueryable代码”:
public List<UserDto> GetUsersByFilters(
String ssn,
List<Guid> orderIds,
List<MaritalStatusEnum> maritalStatuses,
String name,
int age
)
{
using (MyProjEntities entities = new MyProjEntities())
{
IQueryable<User> users = entities.Users;
// Filter By SSN (check if the user's ssn matches)
if (String.IsNullOrEmusy(ssn) == false)
users = users.Where(us => us.SSN == ssn);
// Filter By Orders (check fi the user has all the orders in the list)
if (orderIds != null)
users = users.Where(us => UserContainsAllOrders(us, orderIds));
// Filter By Marital Status (check if the user has a marital status that is in the filter list)
if (maritalStatuses != null)
users = users.Where(pt => maritalStatuses.Contains((MaritalStatusEnum)us.MaritalStatus));
// Filter By Name (check if the user's name matches)
if (String.IsNullOrEmusy(name) == false)
users = users.Where(us => us.name == name);
// Filter By Age (check if the user's age matches)
if (age > 0)
users = users.Where(us => us.Age == age);
return users.ToList();
}
}
private Boolean UserContainsAllOrders(User user, List<Guid> orderIds)
{
return orderIds.All(orderId => user.Orders.Any(order => order.Id == orderId));
}
Run Code Online (Sandbox Code Playgroud)
如果你想单元测试你的TaskManager类,你应该使用的库dessign模式,注入库如UserRepository或ClientTaskStatusRepository到这个类。然后,不用构造CloseDBEntities对象,您将使用这些存储库并调用其方法,例如:
User currentUser = userRepository.GetUser(loggedInUserId);
ClientTaskStatus taskStatus =
clientTaskStatusRepository.GetTaskStatus(taskId, clientId);
Run Code Online (Sandbox Code Playgroud)
如果您要集成测试您的TaskManager类,则解决方案要简单得多。您只需要CloseDBEntities使用指向测试数据库的连接字符串来初始化对象即可。实现此CloseDBEntities目标的一种方法是将对象注入TaskManager类。
您还需要在每次集成测试运行之前重新创建测试数据库,并用一些测试数据填充它。这可以使用Database Initializer实现。
| 归档时间: |
|
| 查看次数: |
1800 次 |
| 最近记录: |