Shinmera / parachute

An extensible and cross-compatible testing framework.
https://shinmera.github.io/parachute
zlib License
94 stars 9 forks source link

Setup and teardown #19

Open mmontone opened 4 years ago

mmontone commented 4 years ago

Hello.

I'm thinking of using Parachute for testing my application.

I have a db that that I would like to recreate in some context. So, I'm thinking of having a parent test suite, that starts by creating the db (setUp), runs its children tests, and drops the db at the end (teardown).

So, it would be:

Is this possible? If so, how? (I've looked at fixtures, but I don't get them yet.)

Thanks!

Mariano

Shinmera commented 4 years ago

There is currently no way to have parent test forms execute around child test instances.

The easiest way to do what you want is to wrap your test forms in a with-database macro or something similar, or to define a wrapper around define-test that does this.

You could also use the fixtures system by using define-fixture-capture and define-fixture-restore on symbols that name databases, and then annotating your tests with :fix (db-name).

mmontone commented 4 years ago

I've managed to execute around tests with a custom class:

;; test class with setup/teardown support

(defclass around-test (parachute::test)
  ((setup :initarg :setup :accessor setup :initform nil)
   (teardown :initarg :teardown :accessor teardown :initform nil))
  (:documentation "Test class with setup/teardown support"))

(defmethod parachute::eval-in-context :around (context (test around-test))
  (when (setup test)
    (funcall (setup test)))
  (unwind-protect
       (call-next-method)
    (when (teardown test)
      (funcall (teardown test)))))

(defun create-db ()
  (format t "Creating db.."))

(defun drop-db ()
  (format t "Dropping db.."))

(parachute:define-test my-db-test
  :test-class around-test
  :setup create-db
  :teardown drop-db
  (parachute:true (= 1 1) "One is equal to one"))

(parachute:define-test child-db-test
  :parent my-db-test
  :description "Subtest"
  (parachute:fail (error "An expected failure.") error "Expecting failure")
  (parachute:fail (warn "An expected warning.") warning "Expecting warninge"))

(parachute:test 'my-db-test)

Result:

        ? COMMON-LISP-USER::MY-DB-TEST
Creating db..
  0.000 ✔   (true (= 1 1))
        ?   COMMON-LISP-USER::CHILD-DB-TEST
  0.000 ✔     (fail (error "An expected failure.") error)
  0.000 ✔     (fail (warn "An expected warning.") warning)
  0.000 ✔   COMMON-LISP-USER::CHILD-DB-TEST
Dropping db..
  0.001 ✔ COMMON-LISP-USER::MY-DB-TEST

;; Summary:
Passed:     3
Failed:     0
Skipped:    0

It would be nice to consider an extension similar to this perhaps?

Shinmera commented 4 years ago

I feel like an extension to the fixture framework would be the best place for something like this, since you are, in effect, fixing something in place for the duration of a test. I'll have to think on the details, though.

Hexstream commented 4 years ago

I'm not clear on the details but I think the MOP could help here, something to do with a new generic function type and/or method combination type, instead of some idiosyncratic and unintuitive API.

TatriX commented 2 years ago

Has anything changed in the last year with the setup&teardown recommendations?

Shinmera commented 2 years ago

I'm afraid not. I haven't had any time to commit to this, and nobody else has stepped up to the challenge either :)

Shinmera commented 1 year ago

9d91cc9 changed fixtures such that they execute around children as well, allowing the suggested idea in https://github.com/Shinmera/parachute/issues/19#issuecomment-620070283 to work somewhat:

(define-fixture-capture database (name)
  (when (database-p name)
    (create-database name)))

(define-fixture-capture database (name)
  (when (database-p name)
    (drop-database name)))

(define-test database-tests
  :fix (my-db))

(define-test child
  :parent database-tests
  ...)

The only constraint right now is that fixtures are not inherited, meaning if you run the child test directly, it will not trigger the fixture. I'll have to think about how to make that work.