Egenskapsbaserad testning med clojure.test.check
Lär er skriva robusta tester som verifierar egenskaper hos er kod över ett stort antal indata med `clojure.test.check`.
Egenskapsbaserad testning med clojure.test.check är en gratis lektion i Clojure för funktionell programmering och JVM-backendutveckling på CoddyKit. Detta är lektion 3 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för Clojure för funktionell programmering och JVM-backendutveckling, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Clojure för funktionell programmering och JVM-backendutveckling innehåller totalt 4 lektioner.
Bortom enkla exempeltester
Välkommen till Property-Based Testing (PBT)! Traditionella enhetstester använder specifika exempel för att kontrollera om koden fungerar. PBT använder en annan metod.
I stället för exempel definierar du egenskaper som koden alltid ska uppfylla, oavsett indata. Sedan genererar ett PBT-verktyg många varierade indata för att försöka få dessa egenskaper att fallera.
PBT jämfört med exempelbaserad testning
Tänk på det så här:
- Exempelbaserad testning (som
clojure.test): "Returnerar(my-add 2 3)5?" Du väljer indata. - Property-Based Testing (med
clojure.test.check): "Är(my-add a b)alltid lika med(my-add b a)för alla heltalaochb?" Verktyget genereraraochb.
PBT är utmärkt på att hitta specialfall som du kanske inte skulle komma på manuellt.
Definiera en egenskap med for-all
I clojure.test.check definierar du en egenskap med makrot for-all. Det tar en vektor med bindningar (variabler parade med generatorer) och ett predikat (en funktion som ska returnera true om egenskapen gäller).
Prova att köra den här enkla egenskapen som kontrollerar om ett genererat heltal faktiskt är ett heltal.
(ns my-project.core
(:require [clojure.test.check :as tc]
[clojure.test.check.properties :refer [for-all]]
[clojure.test.check.generators :as gen]))
(defn run-int-property-check []
(let [result (tc/quick-check 100
(for-all [x gen/int]
(<= x (inc x))))] ; Property: x is always <= x+1
(println "Property check result:" result)))
(defn -main [& args]
(run-int-property-check))Bygga med generatorer
Generatorer (från clojure.test.check.generators, vanligtvis aliasade som gen) är funktioner som producerar slumpmässiga data av en viss typ. De utgör kärnan i PBT:s indata.
Vanliga generatorer är bland annat gen/int, gen/boolean, gen/string och många fler. Du kan också kombinera dem!
(ns my-project.core
(:require [clojure.test.check.generators :as gen]))
(defn generate-and-print []
(println "Random int:" (gen/generate gen/int))
(println "Random boolean:" (gen/generate gen/boolean))
(println "Random string:" (gen/generate gen/string {:max-size 10}))) ; Limit string size for display
(defn -main [& args]
(generate-and-print))Köra egenskapskontroller
När du har definierat en egenskap med for-all behöver du köra den. clojure.test.check tillhandahåller funktioner som quick-check och check.
tc/quick-check N property: Kör egenskapenNgånger och returnerar en sammanfattning.tc/check property: Ger ett mer detaljerat resultat, vilket är särskilt användbart när en egenskap fallerar.
Här kontrollerar vi om addition är kommutativ (a + b = b + a).
(ns my-project.core
(:require [clojure.test.check :as tc]
[clojure.test.check.properties :refer [for-all]]
[clojure.test.check.generators :as gen]))
(defn check-sum-property []
(let [sum-property (for-all [a gen/int b gen/int]
(= (+ a b) (+ b a)))] ; Addition is commutative
(println "Checking sum property...")
(let [result (tc/quick-check 100 sum-property)]
(println "Result:" result))))
(defn -main [& args]
(check-sum-property))Praktisk egenskap: reversibilitet
En vanlig och kraftfull egenskap att testa är reversibilitet. Om du tillämpar en operation och sedan dess invers bör du få tillbaka den ursprungliga indatan.
Vi definierar enkla funktioner, encode och decode (som bara vänder på en sträng), och kontrollerar om (decode (encode s)) alltid ger s.
(ns my-project.core
(:require [clojure.test.check :as tc]
[clojure.test.check.properties :refer [for-all]]
[clojure.test.check.generators :as gen]))
(defn encode [s] (apply str (reverse s))) ; Simple reverse string
(defn decode [s] (apply str (reverse s)))
(defn check-encode-decode-property []
(let [prop (for-all [s (gen/string-alphanumeric 0 20)] ; Limit string size
(= s (decode (encode s))))]
(println "Checking encode/decode property...")
(let [result (tc/quick-check 100 prop)]
(println "Result:" result))))
(defn -main [& args]
(check-encode-decode-property))Hitta minimala fel (förminskning)
En av de mest värdefulla funktionerna i clojure.test.check är förminskning. När en egenskap fallerar ger den dig inte bara den första felande indatan. Den försöker hitta den minsta möjliga indatan som fortfarande orsakar felet.
Det hjälper dig att snabbt hitta grundorsaken till ett fel. Kör det här exemplet: my-buggy-function har ett subtilt fel när indatan är 0.
(ns my-project.core
(:require [clojure.test.check :as tc]
[clojure.test.check.properties :refer [for-all]]
[clojure.test.check.generators :as gen]))
(defn my-buggy-function [x]
(if (= x 0) 100 x)) ; Bug: returns 100 if input is 0
(defn check-buggy-property []
(let [prop (for-all [x gen/int]
(> (my-buggy-function x) 0))] ; Property: result is always > 0
(println "Checking buggy property (expecting failure)...")
(let [result (tc/quick-check 100 prop)]
(println "Result (look for 'smallest' failing input):" result))))
(defn -main [& args]
(check-buggy-property))Skapa anpassade generatorer
Du är inte begränsad till grundläggande generatorer. Du kan kombinera dem eller omvandla deras utdata för att skapa generatorer för mer specifika datatyper med funktioner som gen/fmap och gen/such-that.
gen/fmap (funktoriell mappning) tillämpar en funktion på värdet som produceras av en annan generator. Här skapar vi en generator för positiva heltal.
(ns my-project.core
(:require [clojure.test.check :as tc]
[clojure.test.check.properties :refer [for-all]]
[clojure.test.check.generators :as gen]))
(def gen-positive-int
(gen/fmap #(inc %) gen/nat)) ; gen/nat produces non-negative numbers, inc makes them positive
(defn check-positive-property []
(let [prop (for-all [x gen-positive-int]
(> x 0))] ; Property: x is always greater than 0
(println "Checking positive integer property...")
(let [result (tc/quick-check 100 prop)]
(println "Result:" result))))
(defn -main [& args]
(check-positive-property))Kombinera generatorer
För komplexa datastrukturer kan du kombinera flera generatorer. gen/vector skapar en vektor med genererade element, gen/tuple skapar en sekvens med fast storlek och gen/hash-map skapar mappar med genererade nycklar och värden.
Här är ett exempel på hur du genererar enkla data för en ”person”.
(ns my-project.core
(:require [clojure.test.check.generators :as gen]))
(def gen-person
(gen/hash-map :name (gen/string-alphanumeric 3 10)
:age (gen/choose 1 100)))
(defn generate-people []
(println "Generating 3 people:")
(dotimes [n 3]
(println " " (gen/generate gen-person))))
(defn -main [& args]
(generate-people))Kontrollera dina kunskaper
Property-Based Testing förändrar i grunden hur vi ser på testindata.
Sammanfattning: robust testning med PBT
I den här lektionen utforskade vi Property-Based Testing med clojure.test.check.
- Du lärde dig att definiera egenskaper med
for-all. - Vi såg hur generatorer (
gen/int,gen/stringoch så vidare) skapar varierade indata. - Du använde
quick-checkför att köra dina egenskaper. - Vi diskuterade kraften i förminskning för att hitta minimala fall som orsakar fel.
- Slutligen lärde du dig att skapa och kombinera anpassade generatorer för komplexa data.
PBT är ett kraftfullt verktyg för att skriva mer robusta och tillförlitliga Clojure-applikationer genom att testa beteenden över ett oändligt intervall av indata!
Lär dig Clojure med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 12
- Lektioner
- 48
Vanliga frågor
Är lektionen ”Egenskapsbaserad testning med clojure.test.check” gratis?
Ja – hela texten till ”Egenskapsbaserad testning med clojure.test.check” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i Clojure för funktionell programmering och JVM-backendutveckling, kan Ni uppgradera till CoddyKit PRO. Kursen i Clojure för funktionell programmering och JVM-backendutveckling innehåller totalt 4 lektioner.
Vad lär jag mig i ”Egenskapsbaserad testning med clojure.test.check”?
Lär er skriva robusta tester som verifierar egenskaper hos er kod över ett stort antal indata med `clojure.test.check`. Ni övar på Clojure för funktionell programmering och JVM-backendutveckling med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig Clojure för funktionell programmering och JVM-backendutveckling?
Du behöver inga förkunskaper. Utbildningen i Clojure för funktionell programmering och JVM-backendutveckling på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 3 av 4.
Hur lång tid tar lektionen ”Egenskapsbaserad testning med clojure.test.check”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här Clojure för funktionell programmering och JVM-backendutveckling-lektionen?
Ja. Varje Clojure för funktionell programmering och JVM-backendutveckling-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.
Alla lektioner i den här kursen
- Transducers för effektiv bearbetning
- Monader och funktionella abstraktioner
- Egenskapsbaserad testning med clojure.test.check
- Lata sekvenser och oändliga strömmar