私は1つのことについて非常に多く(何十もの投稿)を読みました:
Entity Framework コードを含むビジネス ロジック コードを単体テストする方法。
私は3つのレイヤーを持つWCFサービスを持っています:
- サービス層
- ビジネスロジックレイヤー
- データ アクセス層
私のビジネス ロジックは、すべてのデータベース操作にDbContextを使用します。私のエンティティはすべてPOCOになりました(以前はObjectContextでしたが、変更しました)。
Ladislav Mrnka の回答hereとhereを読んで、 DbContextをモック \ 偽造してはならない 理由について説明しました。
彼は次 のように述べています。
そして: 「確かに、あなたのアプローチはいくつかのケースで機能しますが、ユニットテスト戦略はすべてのケースで機能する必要があります-それを機能させるには、テストされたメソッドから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();
}
}
}
添付のコードには、私のビジネス ロジックからの関数のデモがあります。関数には、データベースへの「トリップ」がいくつかあります。この関数から EF コードを別のアセンブリに取り除く方法を正確に理解していないため、この関数の単体テスト(EF データの代わりにいくつかの偽のデータを挿入することによって) と、アセンブリの統合テストを行うことができます。 「EF関数」が含まれています。
Ladislav または他の誰かが助けてくれますか?
[編集]
これは私のビジネス ロジックのコードの別の例です。テスト済みのメソッドから「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));
}