как провести юнит-тест на лень

У меня есть функция, которая должна принимать ленивую последовательность и возвращать нереализованную ленивую последовательность. Теперь я хочу написать модульный тест (кстати, test-is), чтобы убедиться, что результатом является нереализованная ленивая последовательность.


person Arthur Ulfeldt    schedule 30.10.2009    source источник
comment
Как насчет того, чтобы дать нам код функции. Киньте нам кость.   -  person Kelly S. French    schedule 30.10.2009
comment
Возможно, он имеет в виду очередь перед бюро по безработице? малый том хай-хэт   -  person Jeff Meatball Yang    schedule 31.10.2009
comment
Нереализованная ленивая последовательность, история моей жизни.   -  person Brian Carper    schedule 31.10.2009
comment
У меня есть много разных функций, которые я хотел бы протестировать с этим. Я действительно ищу макрос assert-is-lazy для test-is   -  person Arthur Ulfeldt    schedule 31.10.2009


Ответы (2)


user=> (instance? clojure.lang.LazySeq (map + [1 2 3 4] [1 2 3 4]))
true

Если у вас есть много вещей для тестирования, возможно, это упростит это:

(defmacro is-lazy? [x] `(is (instance? clojure.lang.LazySeq ~x)))

user=> (is-lazy? 1)

FAIL in clojure.lang.PersistentList$EmptyList@1 (NO_SOURCE_FILE:7)
expected: (clojure.core/instance? clojure.lang.LazySeq 1)
  actual: (not (clojure.core/instance? clojure.lang.LazySeq 1))
false
user=> (is-lazy? (map + [1 2 3 4] [1 2 3 4]))
true

Начиная с Clojure 1.3, есть также функция realized?: «Возвращает true, если значение было создано для обещания, задержки, будущей или ленивой последовательности».

person Timothy Pratley    schedule 01.11.2009
comment
Похоже, это не работает. iterate возвращает ленивую последовательность, но (instance? clojure.lang.LazySeq (iterate inc 10)) => false - person Ruslan; 01.02.2016
comment
Я все еще изучаю Clojure, но не значит ли это, что этот подход не универсален? Итак, может быть много разных реализаций лени, верно? Итак, похоже, что другой ответ (с проверкой побочных эффектов) более универсален. Но дайте мне знать, если я что-то пропустил здесь. - person Ruslan; 03.02.2016
comment
Да, ты прав. Также теперь есть лучший способ ответить на этот вопрос; функция realized? (добавленная в версии 1.3) будет обрабатывать все незавершенные дела. Примечательно (понял? (повторить вкл. 10)) => правда. Я предполагаю, что правильно называть это ленивой последовательностью, но первый элемент должен быть реализован, потому что он передается в качестве аргумента, поэтому избежать этого невозможно. Я думаю, что тестирование возвращаемого типа соответствует целям вопроса и менее навязчиво, чем альтернатива. - person Timothy Pratley; 04.02.2016
comment
Какой смысл использовать здесь макрос, если можно использовать функцию? Разве (defn is-lazy [x] (is (instance? clojure.lang.LazySeq x)) не будет работать так же? - person bfontaine; 13.09.2016
comment
@bfontaine Да, функция работает хорошо. При написании тестов вы часто хотите, чтобы результат сбоя ясно показал вам, что пошло не так. Аргументы функции оцениваются, поэтому в отчете об ошибках будет напечатано переданное значение, а не форма, которая была передана. В то время как с макросом исходная форма сохраняется без оценки, поэтому отчет об ошибках немного яснее. Например, (is-lazy? (vec (map inc (range 10)))) в качестве макроса сообщит expected: (clojure.core/instance? clojure.lang.LazySeq (vec (map inc (range 10)))), но функция покажет [1 2 3 4 5 6 7 8 9 10]... просто вопрос предпочтений. - person Timothy Pratley; 13.09.2016

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

Во-первых, настройте его следующим образом:

(def effect-count (ref 0))

(defn test-fn [x]
    (do
        (dosync (alter effect-count inc))
        x))

Затем запустите свою функцию. Я просто использую карту, здесь:

(def result (map test-fn (range 1 10)))

Проверьте, запускался ли test-fn:

(if (= 0 @effect-count) 
    (println "Test passed!")
    (println "Test failed!"))

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

(dorun result)

И снова проверьте значение счетчика эффектов. На этот раз мы ДЕЙСТВИТЕЛЬНО ожидаем, что побочный эффект сработает. А, это так...

user=>@effect-count
9
person levand    schedule 31.10.2009
comment
Я ищу способ протестировать любую функцию, а не функцию для тестирования - person Arthur Ulfeldt; 10.12.2009