Pruebas unitarias EF - ¿Cómo extraer el código EF de BL?

he leídotanto (docenas de publicaciones) sobre una cosa:

Cómo realizar una prueba unitaria del código de lógica empresarial que tiene un código de Entity Framework.

Tengo un servicio WCF con 3 capas:

Capa de servicioCapa de logica de negociosCapa de acceso a datos

Mi lógica de negocios usa elDbContext Para todas las operaciones de base de datos. Todas mis entidades ahora son POCOs (solían ser ObjectContext, pero cambié eso).

he leídoDe Ladislav Mrnka responderaquí yaquí sobre las razones por las que deberíamosno simulacro de falsificar elDbContext.

Él dijo:"Esa es la razón por la que creo que el código relacionado con el contexto / Linq-to-entera debe cubrirse con pruebas de integración y trabajar contra la base de datos real".

y:"Claro, su enfoque funciona en algunos casos, pero la estrategia de prueba unitaria debe funcionar en todos los casos: para que funcione, debe mover EF e IQueryable completamente de su método probado".

Mi pregunta es, ¿cómo lograr esto?

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

En el código adjunto hay una demostración de una función de mi lógica de negocios. La función tiene varios 'viajes' a la base de datos. No entiendo cómo puedo exactamentetira El código EF de esta función sale a un ensamblaje separado, para que yo puedaprueba de unidad esta función (al inyectar algunos datos falsos en lugar de los datos de EF), yprueba de integración El conjunto que contiene las 'funciones EF'.

¿Puede ayudar Ladislav o alguien más?

[Editar]

Aquí hay otro ejemplo de código de mi lógica de negocios, no entiendo cómo puedo 'mover el código de EF e IQueryable' desde mi método probado:

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

Respuestas a la pregunta(2)

Su respuesta a la pregunta