When developing with the object framework, I end up excreting all the side-effect-free (SEF) code from the object. Remember the reason for an object is to encapsulate state.
(defun format-results (result-totals) (destructuring-bind (result-totals asserts passes errors elapses) result-totals (list (format nil "~A Total Test(s)" result-totals) (format nil "~A Assertions" asserts) (format nil "~A Passes" passes) (format nil "~A Failures" (- asserts passes)) (format nil "~A Errors" errors) (format nil "~,3F Second(s)" elapses)))) (defun result-sums (result-totals) (loop for (nil assert pass error elapse) in result-totals summing assert into asserts summing pass into passes summing error into errors summing elapse into elapses finally (return (list (length result-totals) asserts passes errors elapses)))) (defobj results-model (:members ((database nil))) (:methods ((:get-result-totals () (format-results (result-sums (retrieve-totals database)))) (:connect-db (db) (setf database db)) (:insert-result-data (result-data) (add-result database result-data))))
This method really it makes it easier to test the SEF functions. When using the object’s methods for interacting with state during tdd, you have to maintain a reference to the object. By excreting the functionality out of the object, you no longer need the reference. You just test for functionality.
(test-fixture :format-results (:tests (should-return-format-results-empty (assert-equal '("0 Total Test(s)" "0 Assertions" "0 Passes" "0 Failures" "0 Errors" "0.000 Second(s)") (format-results (list 0 0 0 0 0)))))) (test-fixture :result-sums (:tests (should-return-no-sums (assert-equal '(1 0 0 0 0) (result-sums (list (list :no-name 0 0 0 0))))) (should-return-sums (assert-equal '(2 1 1 1 0.15100001) (result-sums (list (list :t1 0 0 1 0.001) (list :t2 1 1 0 0.15))))))) (test-fixture :results-model (:setup ((db (make-database)) (model (make-results-model))) (connect-db model db)) (:tests (should-transmit-result-totals (let ((totals '("0 Total Test(s)" "0 Assertions" "0 Passes" "0 Failures" "0 Errors" "0.000 Second(s)"))) (assert-equal totals (get-result-totals model)))) (should-insert-result-data (let ((totals '("1 Total Test(s)" "1 Assertions" "1 Passes" "0 Failures" "0 Errors" "0.000 Second(s)"))) (insert-result-data model (list :no-name 1 1 0 0.0)) (assert-equal totals (get-result-totals model))))))
This is very conducive to programming incrementally.
The function we want to look at is get-result-totals. This function retrieve the totals from the database. We pass this then to result-sums. It’s results are then passed to format-results.
- Retrieve results from database.
- Sum results.
- Format results.
Happy January!