Статьи

Clojure: ожидания — устранение дублирования с учетом

ожидания, очевидно, имеют тенденцию к одному утверждению на тест ; однако бывают случаи, когда проверка нескольких вещей одновременно имеет смысл. Например, если вы хотите проверить несколько разных свойств одного и того же объекта Java, возможно, имеет смысл сделать несколько утверждений в одном экземпляре.

Одна из самых больших проблем с несколькими утверждениями на тест — это когда ваш тест следует такой схеме:

  1. создать какое-то государство
  2. проверить немного о состоянии
  3. изменить состояние
  4. проверить больше о состоянии

Частично проблема заключается в том, что утверждения, которые произошли до изменения состояния, могут иметь или не иметь значение после изменения. Кроме того, если какое-либо из утверждений не выполнено, вы должны прекратить выполнение всего теста — таким образом, некоторые из ваших утверждений не будут выполнены (и вам будет не хватать некоторой информации).

Ожидания выбирают альтернативный путь — поддерживая идею множественных утверждений, предоставляя специальный синтаксис, который позволяет проводить множественные проверки и наименьшее количество дублирования.

В следующем примере показано, как можно протестировать несколько свойств объекта Java с использованием синтаксиса «данного».

(given (java.util.ArrayList.)
       (expect
         .size 0
         .isEmpty true))

jfields$ lein expectations
Ran 2 tests containing 2 assertions in 4 msecs
0 failures, 0 errors.

Синтаксис достаточно прост: (заданный объект-объект (ожидаемое возвращаемое значение метода [возвращаемое значение метода]))

примечание: [возвращаемое значение метода] может повторяться любое количество раз.

Этот синтаксис позволяет нам ожидать возвращаемые значения от стольких методов, сколько мы хотим проверить, но призывает нас не менять никакого состояния между нашими различными утверждениями. Этот синтаксис также позволяет нам запускать каждое утверждение независимо от результата любого предыдущего утверждения.

Очевидно, вы можете вызывать методы, которые изменяют внутреннее состояние объекта, и в этот момент вы сами по себе. Я определенно не рекомендую тестировать таким образом. Тем не менее, до тех пор, пока вы вызываете методы, которые не изменяют любое состояние «данное», вы можете писать краткие тесты, которые проверяют столько аспектов объекта, сколько вам необходимо протестировать.

Как обычно, я покажу вывод для тестов, которые не работают с использованием этого синтаксиса.

(given (java.util.ArrayList.)
       (expect
         .size 1
         .isEmpty false))

jfields$ lein expectations
failure in (core.clj:4) : sample.test.core
           (expect 1 (.size (java.util.ArrayList.)))
           expected: 1 
                was: 0
failure in (core.clj:4) : sample.test.core
           (expect false (.isEmpty (java.util.ArrayList.)))
           expected: false 
                was: true

Этот специфический синтаксис был создан для тестирования объектов Java, но интересным побочным эффектом является то, что он фактически работает с любым значением, и вы можете заменить вызовы метода любой функцией. Например, вы можете проверить вектор или карту, используя приведенные ниже примеры в качестве шаблона.

(given [1 2 3]
       (expect
         first 1
         last 3))

(given {:a 2 :b 4}
       (expect 
         :a 2
         :b 4))

jfields$ lein expectations
Ran 4 tests containing 4 assertions in 8 msecs
0 failures, 0 errors.

И, конечно же, неудачи.

(given [1 2 3]
       (expect
         first 2
         last 1))

(given {:a 2 :b 4}
       (expect 
         :a 1
         :b 1))

jfields$ lein expectations
failure in (core.clj:4) : sample.test.core
           (expect 2 (first [1 2 3]))
           expected: 2 
                was: 1
failure in (core.clj:4) : sample.test.core
           (expect 1 (last [1 2 3]))
           expected: 1 
                was: 3
failure in (core.clj:9) : sample.test.core
           (expect 1 (:a {:a 2, :b 4}))
           expected: 1 
                was: 2
failure in (core.clj:9) : sample.test.core
           (expect 1 (:b {:a 2, :b 4}))
           expected: 1 
                was: 4
Ran 4 tests containing 4 assertions in 14 msecs
4 failures, 0 errors.

Когда вы хотите вызывать методы объекта Java или вызывать функции с одним и тем же экземпляром снова и снова, предыдущий заданный синтаксис — это действительно простое решение. Однако бывают моменты, когда вы хотите что-то более гибкое.

У ожидаемых также есть «заданный» синтаксис, который позволяет указывать шаблон — тем самым уменьшая дублирование кода. В следующем примере показан тест, который проверяет + с различными аргументами.

(given [x y] (expect 10 (+ x y))
       4 6
       6 4
       12 -2)

jfields$ lein expectations
Ran 3 tests containing 3 assertions in 5 msecs
0 failures, 0 errors.

Синтаксис для данного вида данных: (заданные привязки значений шаблонной формы). Форма шаблона может быть чем угодно — просто не забудьте указать ожидаемый результат.

Вот еще один пример, где мы комбинируем данные с, чтобы проверить несколько разных вещей. Этот пример показывает как успешную, так и неудачную версии.

;; successful
(given [x y] (expect x (in y))
       :a #{:a :b}
       {:a :b} {:a :b :c :d})

;; failure
(given [x y] (expect x (in y))
       :c #{:a :b}
       {:a :d} {:a :b :c :d})

lein expectations
failure in (core.clj:8) : sample.test.core
           (expect :c (in #{:a :b}))
           key :c not found in #{:a :b}
failure in (core.clj:8) : sample.test.core
           (expect {:a :d} (in {:a :b, :c :d}))
           expected: {:a :d} 
                 in: {:a :b, :c :d}
           :a expected: :d
                   was: :b
Ran 4 tests containing 4 assertions in 13 msecs
2 failures, 0 errors.

Это в основном так для «данного» синтаксиса в рамках ожиданий. Есть моменты, когда я использую все различные версии данных; однако, кажется, существует связь с использованием данных и взаимодействием с объектами Java. Если вы не пользуетесь объектами Java очень часто, вам, вероятно, не понадобится большая отдача.

 

С http://blog.jayfields.com/2011/11/clojure-expectations-removing.html