Wie man localStorage in JavaScript-Einheitentests verspottet?
Lesezeit: 6 Minuten
Anthony Sotile
Gibt es irgendwelche Bibliotheken da draußen zu verspotten localStorage?
Ich habe verwendet Sinon.JS für die meisten habe ich andere javascript verspottet und fand es echt toll.
Meine ersten Tests zeigen, dass localStorage sich weigert, in Firefox (sadface) zuweisbar zu sein, also brauche ich wahrscheinlich eine Art Hack dafür:/
Meine Optionen ab jetzt (wie ich sehe) sind wie folgt:
Erstellen Sie Wrapping-Funktionen, die mein gesamter Code verwendet, und verspotten Sie diese
Erstellen Sie eine Art (möglicherweise komplizierte) Zustandsverwaltung (Snapshot von localStorage vor dem Test, bei der Bereinigung, Wiederherstellungs-Snapshot) für localStorage.
??????
Was halten Sie von diesen Ansätzen und glauben Sie, dass es andere bessere Möglichkeiten gibt, dies zu erreichen? In jedem Fall werde ich die resultierende “Bibliothek”, die ich am Ende erstelle, auf Github für Open-Source-Güte stellen.
Du hast #4 verpasst: Profit!
– Chris Laplante
14. Juli 2012 um 16:27 Uhr
Andreas Köberle
Hier ist eine einfache Möglichkeit, es mit Jasmine zu verspotten:
Wenn Sie den lokalen Speicher in all Ihren Tests verspotten möchten, deklarieren Sie die beforeEach() oben gezeigte Funktion im globalen Umfang Ihrer Tests (der übliche Ort ist a specHelper.js Skript).
+1 – Sie könnten dies auch mit Sinon tun. Der Schlüssel ist, warum Sie sich die Mühe machen, das gesamte localStorage-Objekt zu verspotten, verspotten Sie einfach die Methoden (getItem und/oder setItem), an denen Sie interessiert sind.
Und was Sie dann tatsächlich tun, ist ungefähr so:
// mock the localStorage
window.localStorage = storageMock();
// mock the sessionStorage
window.sessionStorage = storageMock();
Ab 2016 scheint dies in modernen Browsern nicht zu funktionieren (geprüft Chrome und Firefox); überschreiben localStorage insgesamt nicht möglich.
– jakub.g
13. Januar 2016 um 17:41 Uhr
Ja, das geht leider nicht mehr, aber das würde ich auch behaupten storage[key] || null ist falsch. Wenn storage[key] === 0 es wird zurückkehren null stattdessen. Ich denke, du könntest es tun return key in storage ? storage[key] : null obwohl.
– redbmk
21. Dezember 2016 um 15:10 Uhr
Habe das gerade bei SO! Funktioniert wie ein Zauber – Sie müssen nur localStor auf localStorage zurückändern, wenn Sie sich auf einem echten Server befinden function storageMock() { var storage = {}; return { setItem: function(key, value) { storage[key] = value || ''; }, getItem: function(key) { return key in storage ? storage[key] : null; }, removeItem: function(key) { delete storage[key]; }, get length() { return Object.keys(storage).length; }, key: function(i) { var keys = Object.keys(storage); return keys[i] || null; } }; } window.localStor = storageMock();
– mplungjan
18. Januar 2019 um 10:17 Uhr
@a8m Ich erhalte einen Fehler, nachdem ich den Knoten auf 10.15.1 aktualisiert habe TypeError: Cannot set property localStorage of #<Window> which has only a gettereine Idee wie ich das beheben kann ?
– Tasawer Nawaz
10. April 2019 um 7:15 Uhr
Um setItemes sollte sein storage[key] = ${value}“ statt storage[key] = value || '' weil du es kannst sessionStorage.setItem('foo', undefined) und es wird undefiniert (oder null) als Zeichenfolge gespeichert.
– Tanguy_k
4. März 2020 um 13:16 Uhr
Die aktuellen Lösungen funktionieren nicht in Firefox. Dies liegt daran, dass localStorage von der HTML-Spezifikation als nicht änderbar definiert ist. Sie können dies jedoch umgehen, indem Sie direkt auf den Prototyp von localStorage zugreifen.
Die browserübergreifende Lösung besteht darin, die Objekte zu verspotten Storage.prototype z.B
Anstatt von spyOn(localStorage, ‘setItem’) verwenden
Dein Kommentar sollte mehr Likes bekommen. Vielen Dank!
– Loris Bachert
10. September 2019 um 14:05 Uhr
Einverstanden, dies ist die beste Antwort, um das Problem auch mit Prebid-PRs anzugehen!
– Jason Lydon
9. Dezember 2021 um 19:44 Uhr
Claudijo
Ziehen Sie auch die Option in Betracht, Abhängigkeiten in die Konstruktorfunktion eines Objekts einzufügen.
var SomeObject(storage) {
this.storge = storage || window.localStorage;
// ...
}
SomeObject.prototype.doSomeStorageRelatedStuff = function() {
var myValue = this.storage.getItem('myKey');
// ...
}
// In src
var myObj = new SomeObject();
// In test
var myObj = new SomeObject(mockStorage)
Im Einklang mit Mocking und Unit-Tests vermeide ich gerne das Testen der Speicherimplementierung. Zum Beispiel macht es keinen Sinn zu prüfen, ob sich die Speicherdauer erhöht hat, nachdem Sie ein Element eingestellt haben usw.
Da es offensichtlich unzuverlässig ist, Methoden auf dem echten localStorage-Objekt zu ersetzen, verwenden Sie einen “dummen” mockStorage und stubben Sie die einzelnen Methoden wie gewünscht, wie zum Beispiel:
var mockStorage = {
setItem: function() {},
removeItem: function() {},
key: function() {},
getItem: function() {},
removeItem: function() {},
length: 0
};
// Then in test that needs to know if and how setItem was called
sinon.stub(mockStorage, 'setItem');
var myObj = new SomeObject(mockStorage);
myObj.doSomeStorageRelatedStuff();
expect(mockStorage.setItem).toHaveBeenCalledWith('myKey');
Das ist was ich mache…
var mock = (function() {
var store = {};
return {
getItem: function(key) {
return store[key];
},
setItem: function(key, value) {
store[key] = value.toString();
},
clear: function() {
store = {};
}
};
})();
Object.defineProperty(window, 'localStorage', {
value: mock,
});
Benutzer123444555621
Gibt es irgendwelche Bibliotheken da draußen zu verspotten localStorage?
Ich habe nur eins geschrieben:
(function () {
var localStorage = {};
localStorage.setItem = function (key, val) {
this[key] = val + '';
}
localStorage.getItem = function (key) {
return this[key];
}
Object.defineProperty(localStorage, 'length', {
get: function () { return Object.keys(this).length - 2; }
});
// Your tests here
})();
Meine ersten Tests zeigen, dass localStorage sich weigert, in Firefox zuweisbar zu sein
Nur im globalen Kontext. Mit einer Wrapper-Funktion wie oben funktioniert es einwandfrei.
Konrad Calmez
Überschreiben der localStorage Eigentum des Globalen window Objekt, wie in einigen der Antworten vorgeschlagen, funktioniert in den meisten JS-Engines nicht, da sie deklarieren localStorage data-Eigenschaft als nicht beschreibbar und nicht konfigurierbar.
Ich habe jedoch herausgefunden, dass Sie zumindest mit der WebKit-Version von PhantomJS (Version 1.9.8) die Legacy-API verwenden können __defineGetter__ um zu kontrollieren, was passiert, wenn localStorage zugegriffen wird. Trotzdem wäre es interessant, ob das auch in anderen Browsern funktioniert.
var tmpStorage = window.localStorage;
// replace local storage
window.__defineGetter__('localStorage', function () {
throw new Error("localStorage not available");
// you could also return some other object here as a mock
});
// do your tests here
// restore old getter to actual local storage
window.__defineGetter__('localStorage',
function () { return tmpStorage });
Der Vorteil dieses Ansatzes besteht darin, dass Sie den zu testenden Code nicht ändern müssen.
Ich habe gerade bemerkt, dass dies in PhantomJS 2.1.1 nicht funktioniert. 😉
– Konrad Calmez
12. Februar 2016 um 15:04 Uhr
12565300cookie-checkWie man localStorage in JavaScript-Einheitentests verspottet?yes
Du hast #4 verpasst:
Profit!
– Chris Laplante
14. Juli 2012 um 16:27 Uhr