Teste de unidade EF - como extrair o código EF do BL?

eu limuito (dezenas de posts) sobre uma coisa:

Como unidade teste código de lógica de negócios que possui código Entity Framework nele.

Eu tenho um serviço WCF com 3 camadas:

Camada de ServiçoCamada de lógica de negóciosCamada de acesso a dados

Minha lógica de negócios usa oDbContext para todas as operações do banco de dados. Todas as minhas entidades são agora POCOs (costumava ser ObjectContext, mas eu mudei isso).

eu liLadislav Mrnka's respondaAqui eAqui sobre as razões pelas quais devemosnão zombar \ fake oDbContext.

Ele disse:"Essa é a razão pela qual eu acredito que o código que lida com o contexto / Linq-para-entidades deve ser coberto com testes de integração e trabalhar contra o banco de dados real."

e:"Claro, sua abordagem funciona em alguns casos, mas a estratégia de teste de unidade deve funcionar em todos os casos - para fazê-la funcionar, você deve mover EF e IQueryable completamente de seu método testado."

Minha pergunta é - como você consegue isso?

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();
        }
    }
}

No código anexado, há uma demonstração de uma função da minha lógica de negócios. A função tem várias 'viagens' para o banco de dados. Eu não entendo como exatamente eu possofaixa o código EF desta função para uma montagem separada, para que eu possateste de unidade esta função (injetando alguns dados falsos ao invés dos dados EF), eintegrar teste o conjunto que contém as 'funções EF'.

Ladislav ou qualquer outra pessoa pode ajudar?

[Editar]

Aqui está outro exemplo de código da minha lógica de negócios, não entendo como posso 'mover o código EF e IQueryable' para fora do meu método testado:

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));
}

questionAnswers(2)

yourAnswerToTheQuestion