Unit Testing EF - Wie kann man EF-Code aus BL extrahieren?

ich habe gelesenso sehr (Dutzende von Beiträgen) über eine Sache:

Unit-Test von Geschäftslogikcode mit Entity Framework-Code.

Ich habe einen WCF-Dienst mit 3 Schichten:

Service-SchichtBusiness Logic LayerDatenzugriffsschicht

Meine Geschäftslogik verwendet dieDbContext für alle Datenbankoperationen. Alle meine Entitäten sind jetzt POCOs (früher ObjectContext, aber das habe ich geändert).

ich habe gelesenLadislav Mrnkas AntwortenHier undHier über die Gründe, warum wir solltennicht verspotten \ fälschen dieDbContext.

Er sagte:"Aus diesem Grund bin ich der Meinung, dass Code, der sich mit Kontext / Linq-to-Entities befasst, mit Integrationstests abgedeckt werden und gegen die reale Datenbank arbeiten sollte."

und:"Sicher, Ihr Ansatz funktioniert in einigen Fällen, aber die Unit-Test-Strategie muss in allen Fällen funktionieren. Damit dies funktioniert, müssen Sie EF und IQueryable vollständig von Ihrer getesteten Methode entfernen."

Meine Frage ist - wie erreicht man das ???

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

Im beigefügten Code ist eine Demonstration einer Funktion aus meiner Geschäftslogik enthalten. Die Funktion hat mehrere "Trips" in die Datenbank. Ich verstehe nicht, wie genau ich kannStreifen den EF-Code von dieser Funktion in eine separate Baugruppe ausgeben, damit ich das kannGerätetest diese Funktion (durch Injizieren einiger gefälschter Daten anstelle der EF-Daten) undTest integrieren die Assembly, die die 'EF-Funktionen' enthält.

Kann Ladislav oder sonst jemand helfen?

[Bearbeiten]

Hier ist ein weiteres Beispiel für Code aus meiner Geschäftslogik. Ich verstehe nicht, wie ich EF- und IQueryable-Code aus meiner getesteten Methode entfernen kann:

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

Antworten auf die Frage(2)

Ihre Antwort auf die Frage