2017-01-10 4 views
5

Wie testen eine Funktion, die Ausgabe ist zufällig mit Jest? Wie folgt aus:Wie testen Sie eine Funktion, die Ausgabe ist zufällig mit Jest?

import cuid from 'cuid'; 
const functionToTest = (value) => ({ 
    [cuid()]: { 
     a: Math.random(), 
     b: new Date().toString(), 
     c: value, 
    } 
}); 

So ist die Ausgabe von functionToTest('Some predictable value') wird so etwas wie:

{ 
    'cixrchnp60000vhidc9qvd10p': { 
    a: 0.08715126430943698, 
    b: 'Tue Jan 10 2017 15:20:58 GMT+0200 (EET)', 
    c: 'Some predictable value' 
    }, 
} 
+1

Was glauben Sie, "Test ... dieser Ausgang ist zufällig" bedeutet sogar? Wirf eine Münze und du könntest zweimal hintereinander Köpfe bekommen; Wenn das nicht möglich ist, ist es nicht zufällig. Der Punkt "zufällig" ist * Sie wissen nicht, welchen Wert Sie suchen *. In der Praxis könnten Sie die Funktion zweimal für die gleiche Eingabe ausführen und unterschiedliche Ausgaben erwarten, aber einige (sehr niedrige) Prozentsätze der Zeit, die es sogar mit funktionierendem Code ausfallen sollte. –

+0

Sicher, Test Zufälligkeit ist ein Unsinn. Ich frage, wie man solche Fälle prinzipiell testen kann. Ich habe nur keine Ahnung, wie das geht. –

+0

Der Schlüssel ist hier Test, keine Zufälligkeit. Vielleicht muss der zufällige Teil weggelassen werden oder so. Ich bin ein Noob beim Testen, also habe eine noob Frage. –

Antwort

12

Hier ist, was ich am Anfang meiner Testdatei setzen:

const mockMath = Object.create(global.Math); 
mockMath.random =() => 0.5; 
global.Math = mockMath; 

In Tests aus dieser Datei ausführen, Math.random immer wieder 0.5.

Volle Kredit sollte dazu für die Idee gehen: https://stackoverflow.com/a/40460395/2140998, die verdeutlicht, dass dieses Überschreiben ist testspezifisch. Mein Object.create ist nur mein zusätzliches Extra ein wenig Vorsicht, die Manipulation an den Interna von Math selbst zu vermeiden.

+0

süß! Ich wünschte, das wäre in der Dokumentation. – looshi

3

ich mich fragen, würde die folgenden Fragen:

  • Sie wirklich zufällige Ausgabe ich testen müssen ? Wenn ich müsste, würde ich sehr wahrscheinlich Bereiche testen oder sicherstellen, dass ich eine Nummer in einem gültigen Format erhalten habe, nicht den Wert selbst
  • Ist es genug, um den Wert für c zu testen?

Manchmal gibt es eine Möglichkeit, die Erzeugung des Zufallswertes in einem Mock und außer Kraft gesetzt, die Erzeugung in Ihrem Test zu verkapseln nur bekannte Werte zurückzukehren. Dies ist eine gängige Praxis in meinem Code. How to mock a constructor like new Date() klingt wie ein ähnlicher Ansatz in jestjs.

+0

Großartig, genau das wollte ich wissen. Nicht nur eine direkte Antwort, sondern etwas, das hinter dem Zweck eines Tests steht. Vielen Dank! –

1

Ich habe Stuart Watts Lösung genommen und bin damit gelaufen (und ein bisschen davon weggerissen). Stuart's Lösung ist gut, aber ich war nicht begeistert von der Idee, dass ein Zufallszahlengenerator immer 0.5 ausspuckt - es scheint, als gäbe es Situationen, in denen man auf eine gewisse Abweichung setzt. Ich wollte auch crypto.randomBytes für meine Passwort-Salze (mit Jest Server-Seite) spotten. Ich verbrachte ein bisschen Zeit damit, also dachte ich, ich würde das Wissen teilen.

Eines der Dinge, die mir aufgefallen sind, ist, dass, selbst wenn Sie einen wiederholbaren Strom von Zahlen haben, die Einführung eines neuen Anrufs zu Math.random() alle nachfolgenden Aufrufe vermasseln könnte. Ich habe einen Weg gefunden, dieses Problem zu umgehen. Dieser Ansatz sollte auf ziemlich jede beliebige Sache angewendet werden können, die Sie verspotten müssen.

(Randbemerkung: Wenn Sie diese stehlen wollen, werden Sie Chance.js installieren müssen - yarn/npm add/install chance)

Math.random zu verspotten, dieses in eine der Dateien an, indem Sie Ihre package.json wies ‚s {"jest":{"setupFiles"} Array:

Sie werden feststellen, dass Math.random() jetzt einen Parameter hat - ein Seed. Dieser Seed kann eine Zeichenfolge sein. Das bedeutet, dass Sie während des Schreibens Ihres Codes den gewünschten Zufallszahlengenerator nach Namen aufrufen können. Als ich dem Code einen Test hinzufügte, um zu überprüfen, ob das funktionierte, habe ich keinen Seed gesetzt. Es vermasselte meine zuvor gespotteten Math.random() Schnappschüsse. Aber dann, als ich es zu Math.random('mathTest') änderte, erzeugte es einen neuen Generator, der "mathTest" genannt wurde und hörte ab, die Reihenfolge vom Standard abzufangen.

Ich habe auch crypto.randomBytes für mein Passwort Salze verspottet. Wenn ich also den Code schreibe, um meine Salze zu erzeugen, schreibe ich vielleicht crypto.randomBytes(32, 'user sign up salt').toString('base64'). Auf diese Weise kann ich ziemlich sicher sein, dass kein nachfolgender Anruf bei crypto.randomBytes meine Sequenz durcheinander bringt.

Wenn jemand sonst auf diese Weise crypto spotten möchte, hier ist wie. Diesen Code in <rootDir>/__mocks__/crypto.js:

const crypto = require.requireActual('crypto') 
const Chance = require('chance') 

const chances = {} 

const mockCrypto = Object.create(crypto) 
mockCrypto.randomBytes = (size, seed = 42, callback) => { 
    if (typeof seed === 'function') { 
    callback = seed 
    seed = 42 
    } 

    chances[seed] = chances[seed] || new Chance(seed) 
    const chance = chances[seed] 

    const randomByteArray = chance.n(chance.natural, size, { max: 255 }) 
    const buffer = Buffer.from(randomByteArray) 

    if (typeof callback === 'function') { 
    callback(null, buffer) 
    } 
    return buffer 
} 

module.exports = mockCrypto 

Und dann jest.mock('crypto') einfach anrufen (wieder, ich habe es in einem meiner "Setupfiles"). Seit ich es veröffentlicht habe, ging ich weiter und machte es kompatibel mit der Callback-Methode (obwohl ich nicht die Absicht habe, es so zu benutzen).

Diese beiden Teile des Codes passieren alle 17 von these tests (I __clearChances__ Funktionen für die beforeEach() s erstellt - es löscht nur alle Schlüssel aus dem chances Hash)

Update: benutze diese für ein paar Tage jetzt und Ich denke, es funktioniert ziemlich gut. Die einzige Sache ist, ich denke, dass vielleicht eine bessere Strategie, um eine Math.useSeed Funktion zu schaffen wäre, dass an der Spitze der Tests laufen gelassen, die Math.random

0

Sie benötigen immer jest-mock-random

verwenden könnte, aber es bietet ein wenig mehr Funktionalität als spöttische es wie in der ersten Antwort vorgeschlagen

Verwandte Themen