6

Tôi đã xem qua Generative Testing in Clojure with spec khái niệm và muốn tìm hiểu về nó.Thử nghiệm sinh sản trong Clojure là gì?

Cũng cung cấp một số ví dụ sẽ rất hữu ích.

+0

Cũng thấy câu này: http://dev.solita.fi/2017/04/10/making-software-testing-easier-with-clojure.html –

Trả lời

11

Khi đọc giới thiệu, chúng tôi có số Rationale and Overview cùng với Guide sẽ cung cấp cho bạn thông tin về cả lý do và cách thức.

Nếu bạn muốn một ví dụ hơi phức tạp, chúng ta có thể lấy string->semantic-version chức năng của leiningen.release:

(defn string->semantic-version [version-string] 
    "Create map representing the given version string. Returns nil if the 
    string does not follow guidelines setforth by Semantic Versioning 2.0.0, 
    http://semver.org/" 
    ;; <MajorVersion>.<MinorVersion>.<PatchVersion>[-<Qualifier>][-SNAPSHOT] 
    (if-let [[_ major minor patch qualifier snapshot] 
      (re-matches 
      #"(\d+)\.(\d+)\.(\d+)(?:-(?!SNAPSHOT)([^\-]+))?(?:-(SNAPSHOT))?" 
      version-string)] 
    (->> [major minor patch] 
     (map #(Integer/parseInt %)) 
     (zipmap [:major :minor :patch]) 
     (merge {:qualifier qualifier 
       :snapshot snapshot})))) 

Phải mất một chuỗi và cố gắng phân tích nó thành một bản đồ chương trình có thể đọc được đại diện cho số phiên bản của một số tạo phẩm. Một spec cho nó có thể trông giống như:

Đầu tiên một số phụ thuộc

(ns leiningen.core.spec.util 
    (:require 
    [clojure.spec   :as spec] 
    [clojure.spec.gen  :as gen] 
    [miner.strgen   :as strgen] 
    [clojure.spec.test  :as test] 
    [leiningen.release  :as release])) 

sau đó một helper vĩ mô

(defmacro stregex 
    "Defines a spec which matches a string based on a given string 
    regular expression. This the classical type of regex as in the 
    clojure regex literal #\"\"" 
    [string-regex] 
    `(spec/with-gen 
    (spec/and string? #(re-matches ~string-regex %)) 
    #(strgen/string-generator ~string-regex))) 

theo sau là một định nghĩa của một phiên bản ngữ nghĩa

(spec/def ::semantic-version-string 
    (stregex #"(\d+)\.(\d+)\.(\d+)(-\w+)?(-SNAPSHOT)?")) 

và một số helper-specs

(spec/def ::non-blank-string 
    (spec/and string? #(not (str/blank? %)))) 
(spec/def ::natural-number 
    (spec/int-in 0 Integer/MAX_VALUE)) 

cho định nghĩa của các phím trong các kết quả bản đồ

(spec/def ::release/major  ::natural-number) 
(spec/def ::release/minor  ::natural-number) 
(spec/def ::release/patch  ::natural-number) 
(spec/def ::release/qualifier ::non-blank-string) 
(spec/def ::release/snapshot #{"SNAPSHOT"}) 

và bản đồ riêng của mình

(spec/def ::release/semantic-version-map 
    (spec/keys :req-un [::release/major ::release/minor ::release/patch 
         ::release/qualifier ::release/snapshot])) 

tiếp theo là chức năng spec:

(spec/fdef release/string->semantic-version 
      :args (spec/cat :version-str ::release/semantic-version-string) 
      :ret ::release/semantic-version-map) 

Bởi bây giờ chúng tôi có thể để Clojure Spec tạo dữ liệu thử nghiệm và đưa nó vào chính hàm đó để kiểm tra xem nó có đáp ứng được nstraints chúng tôi đã đưa lên cho nó:

(test/check `release/version-map->string) 
=> ({:speC#object[clojure.spec$fspec_impl$reify__14248 0x16c2555 "[email protected]"], 
    :clojure.spec.test.check/ret {:result true, 
            :num-tests 1000, 
            :seed 1491922864713}, 
    :sym leiningen.release/version-map->string}) 

Điều này cho chúng ta biết rằng trong số 1000 trường hợp thử nghiệm được tạo ra cho chúng ta hàm truyền qua từng đơn.

+0

lớn câu trả lời.Bạn có thể nói nhiều hơn về nhu cầu về macro trợ giúp so với việc đạt được điều tương tự chỉ bằng cách sử dụng một hàm? –

+0

Macro trợ giúp chỉ tồn tại vì tôi lặp lại mã đó nhiều lần trong suốt mã thế giới thực của mình. Thực sự không có điểm nào trong ví dụ trên ngoại trừ có lẽ là dễ đọc. – Rovanion

6

Bạn có thể thấy dễ nhất để bắt đầu xem clojure/test.check trước khi đi sâu vào Clojure Spec. From the project page:

(require '[clojure.test.check :as tc]) 
(require '[clojure.test.check.generators :as gen]) 
(require '[clojure.test.check.properties :as prop]) 

(def sort-idempotent-prop 
    (prop/for-all [v (gen/vector gen/int)] 
    (= (sort v) (sort (sort v))))) 

(tc/quick-check 100 sort-idempotent-prop) 
;; => {:result true, :num-tests 100, :seed 1382488326530} 

Trong văn xuôi, thử nghiệm này lần đọc: cho tất cả các vectơ của số nguyên, v, v sắp xếp tương đương với sắp xếp v hai lần.

Điều gì xảy ra nếu thử nghiệm của chúng tôi không thành công? test.check sẽ thử và tìm các đầu vào 'nhỏ hơn' mà vẫn không thành công. Quá trình này được gọi là thu hẹp. Hãy xem nó trong hành động:

(def prop-sorted-first-less-than-last 
    (prop/for-all [v (gen/not-empty (gen/vector gen/int))] 
    (let [s (sort v)] 
     (< (first s) (last s))))) 

(tc/quick-check 100 prop-sorted-first-less-than-last) 
;; => {:result false, :failing-size 0, :num-tests 1, :fail [[3]], 
     :shrunk {:total-nodes-visited 5, :depth 2, :result false, 
       :smallest [[0]]}} 
+0

Đẹp Clojure/West 2017 trình bày bởi Eric Normand trên test.check: https://www.youtube.com/watch?v=r5i_OiZw6Sw –

Các vấn đề liên quan