2017-09-15 5 views
2

Je devrais commencer par dire que je suis nouveau à Clojure, et FP en général. J'ai lu la documentation sur la façon de définir les prérequis dans Midje, mais je ne peux pas donner un sens à certaines d'entre elles. J'ai cru comprendre que pour effectuer un TDD top-down, vous devez commencer par écrire un test dans votre module de test, avec une instruction unfinished en haut qui déclare toutes les fonctions prérequises que vous n'avez pas définies encore. Ensuite, vous pouvez jouer avec ces fonctions prérequises dans la fonction provided de votre test (décrivant leurs valeurs de retour et autres). Ma confusion réside dans la façon dont vous êtes censé obtenir votre module source réel pour reconnaître les fonctions prérequises. Voici un exemple très simple et je vais utiliser artificiel pour illustrer mon sens:Comment définir les fonctions prérequises dans Midje?

;;; in my run_game_test module 

    (ns clojure-ttt.run-game-test 
     (:require [midje.sweet :refer :all] 
       [clojure-ttt.run-game :refer [start-game]])) 

    (unfinished do-turns) 

    (fact "`start-game` returns whatever `do-turns` returns" 
     (start-game) => ..winner.. 
     (provided 
     (do-turns) => ..winner..)) 

Et puis de faire le test FAIL correctement, je viens d'écrire un bout d'une fonction dans mon module run_game.

(ns clojure-ttt.run-game) 

    (defn start-game 
     []) 

Jusqu'ici tout va bien. Je cours les tests et ils échouent parce que:
a) do-turns ne s'appelle pas
b) start-game ne retourne rien.

Alors maintenant pour faire passer le test, en changeant start-game pour appeler et retourner (do-turns). Pour l'anecdote, do-turns est une fonction prérequise hypothétique que je vais obtenir à partir d'un module qui n'existe pas encore - ce qui, d'après ce que je comprends, est le fonctionnement du TDD top-down.

(defn start-game 
     [] 
     (do-turns)) 

Maintenant, de manière compréhensible, j'obtiens une énorme erreur; Clojure ne peut pas résoudre le symbole do-turns. Donc j'ai pensé, peut-être si je (declare do-turns) au sommet je pourrais l'empêcher de sauter. Non, j'obtiens une erreur différente parce que j'essaie d'appeler une fonction non liée.

J'ai essayé plusieurs autres moyens pour que Clojure reconnaisse do-turns mais il semble que l'instruction unfinished pose problème. Vais-je juste utiliser unfinished mauvais?

Répondre

1

De l'Midje docs:

unfinished est similaire à declare de Clojure en ce qu'elle peut prendre plusieurs arguments et définir un var pour chacun d'entre eux. Contrairement à déclarer, il lie le var à une fonction qui explose si elle est appelée

Alors, quand vous faites (unfinished do-turns) puis appelez avec (do-turns) une exception est levée:

Erreur #'do-turns [var] a aucune mise en œuvre, mais il a été appelé comme ceci: (do-turns) midje.util.exceptions/user-error (exceptions.clj: 13)

Vous pouvez résoudre ce problème en supprimant le (unfinished do-turns) pa rt et fournir une implémentation de do-turns. Par exemple.,

(ns clojure-ttt.run-game) 

(defn do-turns) 
    []) 

(defn start-game 
    [] 
    (do-turns)) 

et renvoyer dans votre test

(ns clojure-ttt.run-game-test 
    (:require [midje.sweet :refer :all] 
      [clojure-ttt.run-game :refer [start-game do-turns]])) ; <- do-turns 

;; Remove `(unfinished do-turns)` since it is no longer unfinished 

(fact "`start-game` returns whatever `do-turns` returns" 
    (start-game) => ..winner.. 
    (provided 
    (do-turns) => ..winner..)) 
;; => returns true 

Notez que lorsque vous avez fourni une mise en œuvre de do-turns, (unfinished do-turns) lancera une exception car une mise en œuvre existe déjà, il est donc retiré.

Maintenant, vous avez montré qu'un appel à (start-game) renvoie ce que renvoie (do-turns).

+1

Merci, cela fonctionne. Mon seul souci est que, si je mets 'do-turns' dans un espace de noms différent, cela signifie que je devrai importer dans mon module de test à la fois l'espace de noms où' start-game' vit et l'espace de noms où 'do-turns 'vies? Dans OOP, je tiens à importer uniquement la classe à tester dans le répertoire de test correspondant et à mocker les dépendances. Est-ce que ce schéma n'est simplement pas possible à Clojure? –

+1

Oui, si 'do-turns' et' start-game' se trouvent dans des espaces de noms différents, vous devez importer les deux espaces de noms ou donner le nom complet comme 'clojure-ttt.other-namespace/do-turns'. 'provided' utilise [' with-redefs'] (https://clojuredocs.org/clojure.core/with-redefs) et vous devez accéder à var pour l'écraser. Si vous voulez dépendre des abstractions, vous pouvez utiliser des protocoles. –