Sinon: Sandbox löst den Fehler "Nicht vorhandene eigene Eigenschaft kann nicht gestoppt werden" aus.

Erstellt am 18. Aug. 2017  ·  14Kommentare  ·  Quelle: sinonjs/sinon

Ich habe gerade versucht, ein Upgrade von 2.4.1 auf 3.2.1 durchzuführen, und bin auf das folgende Problem gestoßen. Dieser Code funktioniert in 2.4.1:

        const spy = sandbox.spy();
        sandbox.stub(window, 'google').value({
            maps: {
                LatLng: x => x,
                Map: spy
            }
        });

In 3.2.1 wird jedoch eine Ausnahme ausgelöst: TypeError: Cannot stub non-existent own property google

Es wird im Migrationshandbuch nicht erwähnt

Bug Regression

Hilfreichster Kommentar

~ Danke, dass Sie dieses Verhalten wiederhergestellt haben. ~

Wollte einen Anwendungsfall hinzufügen, der das Stubben von nicht vorhandenen Eigenschaften unterstützt.

In meinem Anwendungsfall stubbe ich eine Eigenschaft für ein Konfigurationsobjekt. Das Konfigurationsobjekt verfügt über verschiedene optionale Schlüssel und wird durch Laden einer Datei vom Entwicklercomputer initialisiert. Wenn ich einen bestimmten Test durchführe, muss einer dieser Schlüssel auf einen bekannten Wert gesetzt sein, und dann möchte ich das Entwicklerobjekt so wiederherstellen, wie es war.

sandbox.stub(serverSecrets, 'the_key_i_need_set').value(fakeValue) ist ein sehr klarer Weg, dies zu vermitteln. Es ist gut, dass ich das gleiche Verhalten bekomme, obwohl ich zur Laufzeit nicht weiß, ob der Schlüssel gesetzt ist oder nicht.

Alle 14 Kommentare

Bezogen auf # 1512.

Wenn die Eigenschaft nicht vorhanden ist, müssen Sie sie nicht zur Sandbox hinzufügen. Überschreiben Sie es einfach. Aber ja, wenn es vorher funktioniert hat und wir nicht ausdrücklich gesagt haben, dass es sich ändern sollte, dann ist es eine Regression.

Ich bin mir nicht sicher, was wir hier tun sollen. Aktualisieren Sie die Dokumente, um zu sagen, dass das Stubben nicht vorhandener Werte keinen Sinn ergibt und nicht unterstützt wird, oder machen Sie es möglich?

Wenn die Eigenschaft nicht vorhanden ist, müssen Sie sie nicht zur Sandbox hinzufügen. Überschreiben Sie es einfach.

Das Schöne am Hinzufügen der Eigenschaft zur Sandbox ist, dass sinon mir dann hilft, meine globale Testumgebung zwischen jedem Test über sandbox.restore() sauber zu halten. Dies ist eine äußerst nützliche Funktion, insbesondere bei Bibliotheken von Drittanbietern wie Google Maps, bei denen ich die API nicht kontrolliere. Es wäre großartig, wenn es in der 3.x-Zeile funktionieren könnte.

Ich habe auch gerade bemerkt, dass ich die Sünde begangen habe, kein vollständiges Beispiel zu liefern. Meine Sandbox wird im 2.4.1-Format erstellt:

let sandbox;

before(() => { sandbox = sinon.sandbox.create(); })
afterEach(() => { sandbox.restore(); })

Ich bin mir nicht sicher, ob das wichtig ist. Entschuldigung, dass Sie es nicht früher zur Verfügung gestellt haben.

Ich denke, dass ich in Szenarien wie dem, die @ZebraFlesh beschreibt, es vorziehen würde, wenn die

// not so explicit, doesn't work with [email protected]
beforeEach(function() {
    const spy = sandbox.spy();
    sandbox.stub(window, 'google').value({
        maps: {
            LatLng: x => x,
            Map: spy
        }
    }); 
});
// more explicit, works with sinon<strong i="9">@2</strong>, sinon<strong i="10">@3</strong>
function setGoogleMapsFixture(sandbox) {
    window.google = {
        maps: {
            LatLng: x => x,
            Map: sandbox.spy()
        }
    };
}

function removeGoogleMapsFixture() {
    delete window.google;
}

beforeEach(function() {
    setGoogleMapsFixture(sandbox)
});

// not using afterEach, as this only needs to happen
// after the last test in this block is run
after(function() {
    removeGoogleMapsFixture();
});

Bei einer expliziteren Einstellung des Scheinwerfers wie oben beschrieben benötigen Sie in Sinon keine Funktion, mit der nicht vorhandene eigene Eigenschaften gestoppt werden können.

Ich bin mir nicht sicher, was wir hier tun sollen. Aktualisieren Sie die Dokumente, um zu sagen, dass das Stubben nicht vorhandener Werte keinen Sinn ergibt und nicht unterstützt wird, oder machen Sie es möglich?

Obwohl ich erkenne, dass dies in einigen Szenarien (wie dem von @ZebraFlesh beschriebenen) praktisch sein kann, denke ich, dass das Stubben nicht vorhandener eigener Eigenschaften wahrscheinlich zu Fehlern bei Tests führt, bei denen der Test bestanden wird, weil der Autor den Namen falsch eingegeben hat das bestehende Eigentum, das sie stubben wollten. Wir sollten versuchen, die Möglichkeit von Fehlern zu beseitigen, wo wir können, ohne zu restriktiv zu sein.

Ich denke, das Stubben nicht vorhandener eigener Immobilien sollte nicht unterstützt werden. Wir sollten die Dokumentation aktualisieren.

@mroderick Ich stimme Ihnen darin zu, dass es möglicherweise weniger Fehler gibt, aber wir unterstützen dies bereits für normale Stubs. Wenn wir dieses Verhalten nicht mehr unterstützen wollen, müssen wir es auch dort entfernen, um konsistent zu sein. Es wäre seltsam, diese Funktion nur außerhalb von Sandboxen zu unterstützen, da Sandboxen normalerweise einige Möglichkeiten hinzufügen. Das Entfernen der Stütze ist ein Bruchmerkmal, sodass auch eine größere Beule erforderlich wäre.

Also entweder:

  • Entfernen Sie die Prüfung für Sandboxen umgehend, um diese Fehlerfunktion zu beheben

oder und(?)

  • Entfernen Sie die Funktionalität für normale Stubs und Sandbox-Stubs

    • Veröffentlichung einer neuen Hauptversion mit aktualisierten Dokumenten

Bei einer expliziteren Einstellung des Scheinwerfers wie oben beschrieben benötigen Sie in Sinon keine Funktion, mit der nicht vorhandene eigene Eigenschaften gestoppt werden können.

Ich denke, das funktioniert gut, wenn Ihr Gerät bei Ihren Tests nie variiert. Mein Gerät tut dies jedoch. Ein einfaches Beispiel deckt sowohl Erfolgs- als auch Misserfolgsfälle ab:

it('handles the success case', () => {
        const spy = sandbox.spy();
        sandbox.stub(window, 'google').value({
            maps: {
                LatLng: x => x,
                Map: spy
            }
        });
        // ... test, including asserting that the spy was called
});

it('handles the failure case', () => {
        const msg = 'test error';
        sandbox.stub(window, 'google').value({
            maps: {
                LatLng: x => x,
                Map: sandbox.stub().throws(new Error(msg))
            }
        });
        // ... test, ignoring spy calls and instead focusing on error handling
});

Das Verhalten in 2.x hat den Vorteil, dass nach jedem Test über sandbox.restore() alles richtig bereinigt wird. Wenn Sie das oben beschriebene explizitere Beispiel für die Einrichtung von Geräten verwenden, können Sie die nicht eigene Eigenschaft in einem afterEach -Hook löschen, um den gleichen Effekt zu erzielen.

Um das Problem der Einführung potenzieller Fehler durch versehentliches Eingeben des Namens einer vorhandenen eigenen Eigenschaft zu lösen, könnte sinon die öffentliche API ändern:

  • stub.ownValue() : Stubs besitzen nur eigene Eigenschaften, werfen für nicht eigene Eigenschaften
  • stub.value() : Stubs nur nur nicht eigene Eigenschaften, wirft für eigene Eigenschaften

Die API wird expliziter und der Verbraucher muss das geeignete Tool für die jeweilige Aufgabe auswählen.

Dies hängt sehr stark mit der Diskussion in # 1508 zusammen (obwohl es sich um normale Stubs handelt) h, wo @lucasfcosta die gegenteilige Ansicht hat - dass wir _ nicht für undefined Eigenschaften werfen sollten. Was auch immer wir landen, ich bin fest davon überzeugt, dass wir in den Stubbing-APIs für normale Stubs und Sandboxen konsistent sein müssen. Wir sollten es in einem Fall nicht unterstützen und nicht in dem anderen.

Im Moment ist die Situation:

  • Früher haben normale Stubs 1.x eingeworfen, aber dies hat sich in 2.0 geändert und wirft jetzt nicht mehr
  • Sandkästen haben nicht geworfen, sondern in 3.1 (?) geworfen.

Wir hatten also eine Weile Feature-Parität, aber dann haben wir sie wieder verloren ... Ich denke nicht, dass dieses Zick-Zack-Verfahren für die Benutzer sehr vorteilhaft ist, daher sollten wir diese Diskussion landen. Obwohl ich Morgan darin zustimme, dass dies zu spezifischeren Tests führen könnte, mag ich es nicht, ein Verhalten für zwei Hauptversionen zu löschen und es dann erneut hinzuzufügen. Ich denke, es würde das geringste Rauschen verursachen (Korrekturen für Kunden, Fragen / Probleme auf diesem Tracker), nur um diese Regression rückgängig zu machen.

Obwohl ich die Unannehmlichkeiten verstehe, scheint es eine einfache Problemumgehung mit minimalen Codeänderungen zu geben.

before(function() {
  window.google = 'This is a placeholder for sinon to overwrite.';
});

after(function() {
  delete window.google;
});

Dadurch kann der Sinon-Code unverändert bleiben.

Regression gegen schlechte Dokumentation

Dies scheint ein erwartetes Verhalten zu sein, da es Tests dafür gibt. Wir sollten die Dokumente aktualisieren, um dies meiner Meinung nach widerzuspiegeln. Es kam in einem großen, so dass bahnbrechende Änderungen toleriert werden.

@fearphage Das Beibehalten des Status Quo bedeutet, dass das Stubben nicht vorhandener Felder für Sandboxen nicht unterstützt wird, während das Verhalten für normale Stubs unterstützt wird. Ist es nicht ein bisschen bedauerlich, dass die beiden Funktionssätze nicht übereinstimmen?

Die Auflösung wurde in # 1557 implementiert

Ich habe die verschiedenen Threads gelesen und kann sehen, warum dies passiert ist, aber es ist ein echtes Problem in Typescript, wo Sie häufig Funktionen haben, die auf einem Klassenprototyp implementiert sind. In diesem Fall spuckt sinon den Dummy aus, obwohl alles gut aussieht weise (da keyof YourType gerne alle öffentlichen Funktionen zulässt, die weiter unten in der Prototypenkette definiert sind).

Ich verstehe, dass Typescript für euch wahrscheinlich keine Priorität hat, aber selbst in JS scheint es nicht intuitiv zu sein, dass myObject.callMe() perfekt ausgeführt wird, während sinon.stub(myObject, "callMe") in diesem Fall nicht funktioniert. Ich würde es vorziehen, nicht untersuchen zu müssen, wie dieses bestimmte Objekt zusammengesetzt wurde, nur damit ich weiß, wie man es stoppt.

Ich denke wirklich, dass dies ein wichtiger Anwendungsfall ist, um einen glücklichen Weg zu finden, wenn man bedenkt, dass Klassen in JS mehr native Unterstützung erhalten.

Wenn Sie eine Fehlermeldung erhalten, dass die Methode für das Objekt undefiniert ist, wissen Sie, dass der Fehler wahrscheinlich im Prototyp liegt. Dann scheint das direkte Ändern des Objekts mit myObject.callMe = sinon.stub(); meiner Meinung nach kein so großer Aufwand zu sein ... Sollte Sie auch vor dem Erstellen von Bereinigungs- / Abrissfunktionen bewahren, da der Prototyp nie geändert wurde.

Ja, ich denke, es ist nicht allzu schwierig, das Problem zu umgehen. Es belastet mich nur mehr, wenn ich weiß, wie die Dinge umgesetzt werden.

Es scheint auch nur unerwartet zu sein, so dass ich das Bedürfnis hatte, im Test einen Kommentar hinzuzufügen, um zu erklären, warum der Stubbing-Code in zwei aufeinanderfolgenden Zeilen für dasselbe Objekt unterschiedlich war und warum ich einen der Stubs in meinem Teardown manuell löschte. aber der andere wurde vom Sandkasten gehandhabt.

~ Danke, dass Sie dieses Verhalten wiederhergestellt haben. ~

Wollte einen Anwendungsfall hinzufügen, der das Stubben von nicht vorhandenen Eigenschaften unterstützt.

In meinem Anwendungsfall stubbe ich eine Eigenschaft für ein Konfigurationsobjekt. Das Konfigurationsobjekt verfügt über verschiedene optionale Schlüssel und wird durch Laden einer Datei vom Entwicklercomputer initialisiert. Wenn ich einen bestimmten Test durchführe, muss einer dieser Schlüssel auf einen bekannten Wert gesetzt sein, und dann möchte ich das Entwicklerobjekt so wiederherstellen, wie es war.

sandbox.stub(serverSecrets, 'the_key_i_need_set').value(fakeValue) ist ein sehr klarer Weg, dies zu vermitteln. Es ist gut, dass ich das gleiche Verhalten bekomme, obwohl ich zur Laufzeit nicht weiß, ob der Schlüssel gesetzt ist oder nicht.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen