Aufwand unterstützte Komponententests

c# effort entity-framework-6 unit-testing vstest

Frage

Ich habe einige Tests mit diesem Projekt geerbt. Sie arbeiteten beim Ausführen gegen die SQL-Datenbank, jedoch langsam. Ich versuche, auf Effort umzusteigen.
.NET4.5, EF6.2, Aufwand 1.3.10.

Ich habe zwei mögliche Probleme mit meinen Komponententests.

Es ist egal, ob ich die Tests parallel durchführe oder nicht.

1) Wenn ich mehr als eine laufe, bekomme ich

Das Speichern oder Akzeptieren von Änderungen ist fehlgeschlagen, da mehrere Entitäten vom Typ 'Center.Shared.Person' denselben Primärschlüsselwert haben. Stellen Sie sicher, dass explizit festgelegte Primärschlüsselwerte eindeutig sind. Stellen Sie sicher, dass von der Datenbank generierte Primärschlüssel in der Datenbank und im Entity Framework-Modell ordnungsgemäß konfiguriert sind. Verwenden Sie den Entity Designer für die Konfiguration "Database First / Model First". Verwenden Sie die "HasDatabaseGeneratedOption" -Flüssige API oder "DatabaseGeneratedAttribute" für die Konfiguration von Code First. ---> System.InvalidOperationException: Das Speichern oder Akzeptieren von Änderungen ist fehlgeschlagen, da mehrere Entitäten vom Typ "Center.Shared.Person" denselben Primärschlüsselwert haben. Stellen Sie sicher, dass explizit festgelegte Primärschlüsselwerte eindeutig sind. Stellen Sie sicher, dass die in der Datenbank generierten Primärschlüssel in der Datenbank und im Entity Framework-Modell ordnungsgemäß konfiguriert sind. Verwenden Sie die Konfiguration Entity Designer for Database First / Model First. Verwenden Sie die flüssige API "HasDatabaseGeneratedOption" oder 'DatabaseGeneratedAttribute' für die Konfiguration von Code First ..

Es scheint also, dass die Tests nicht richtig isoliert sind.
Beim Durchlaufen des Codes kann ich sehen, dass CreateTransient aufgerufen wird, aber anscheinend nicht transient genug ist.

    public DbConnection CreateConnection(string nameOrConnectionString)
    {
        lock (_lock)
        {
            if (_connection == null)
            {
                _connection = Effort.DbConnectionFactory.CreateTransient();
            }

            return _connection;
        }
    }

In der TestInitialize-Routine versuche ich, die Datenbank zurückzusetzen.

    [TestInitialize]
    public override void Initialize()
    {
        db.Database.Delete();
        db.Database.CreateIfNotExists();
        db.Database.Initialize(true);

Dies ist ein stark gewundener Code. Wenn wir also mehr Code veröffentlichen müssen, dauert es lange, bis wir an die Unterseite des Kaninchenlochs gelangen. Wahrscheinlich besser, einen PoC zu erstellen.

2) Wenn ich die Tests unabhängig durchführe, bekomme ich ein anderes Problem. Wiederum bestanden diese gegen SQL, aber nicht gegen Aufwand.

    [TestMethod]
    public void ClientAccessorTests_Find()
    {
        Client result;
        Client client = new Client()
        {
            Complete = false,
            HeadOfHousehold = true,
            PersonID = _person.PersonID
        };

        _accessor.Create(client, _accessor.DefaultConnectionContext);

        result = _accessor.Find(new object[] { client.ClientID }, _accessor.DefaultConnectionContext);

        Assert.IsNotNull(result);  // Fails with Assert.IsNotNull failed. 
    }

Erstellen besteht aus

    public virtual EntityType Create(EntityType entity, ConnectionContext connectionContext)
    {
        IsContextValid(connectionContext);
        if (entity == null) throw new ArgumentException("", "entity");

        using (var db = CreateDbContext<DbContextType>(connectionContext))
        {
            db.Set<EntityType>().Add(entity);
            db.SaveChanges();
        }

        return entity;
    }

Finden besteht aus

    public virtual EntityType Find(object[] primaryKey, ConnectionContext connectionContext)
    {
        IsContextValid(connectionContext);
        if (primaryKey == null || primaryKey.Length == 0) throw new ArgumentException("", "primaryKey");

        using (var db = CreateDbContext<DbContextType>(connectionContext))
        {
            return db.Set<EntityType>().Find(primaryKey);
        }
    }

Ich weiß, dass es CreateDbContext aufruft, aber in den Code hineinverfolgt wird, soweit ich das beurteilen kann, scheint es sich um dieselbe Datenbank mit derselben ID zu handeln.

Wodurch sollten die Tests isoliert werden?
Und irgendwelche Ideen, warum Find bei einer In-Memory-Datenbank aufhört zu arbeiten?

Akzeptierte Antwort

Ich habe versucht, den impliziten Ansatz zu verwenden, bei dem alles über Einstellungen in der Datei app.config angeschlossen ist.
Nachdem ich diesen Ansatz aufgegeben und die Datenbankverbindung erstellt und explizit festgelegt hatte, hatte ich mehr Glück.

        System.Data.Common.DbConnection connection = new EffortProviderFactory("").CreateConnection("");
        _accessor = new ClientAccessor();
        _accessor.Connection = connection;
        db = new EntitiesDb(connection);

Der Basis-Accessor erstellt bei jedem Zug Kopien der Datenbank. Dies ist in Ordnung, solange dieselbe DbConnection verwendet wird. Also setze ich das auf den Accessor und verwende es dann hier:

        if (_connection == null) {   // this is the path for the application
            if (connectionContext == null) {
                ret = new T();
            } else {
                ret = (T)Activator.CreateInstance(typeof(T), new object[] { connectionContext });
            }
        } else {  // this is the path for unit tests.
            ret = (T)Activator.CreateInstance(typeof(T), new object[] { _connection });
        }

Schließlich musste ich einen Konstruktor hinzufügen, der eine DbConnection zu DbContext und seinen Nachkommen führte.

    public EntitiesDb(DbConnection connection) : base(connection) { }

'Find' funktioniert jetzt und die Tests stören sich nicht.
Der nächste Schritt besteht darin, dies auf die Basisklassen zu reduzieren.



Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum