1. David Krentzlin
  2. lisp-unleashed blog

Commits

certainty  committed 70d063c

finished raw version

  • Participants
  • Parent commits bcc6e7d
  • Branches default

Comments (0)

Files changed (9)

File _posts/2014-04-05-tesing_your_chicken_code.md

View file
  • Ignore whitespace
 
 Now you're free to add more sophisticated algorithms and test against that model like so:
 
-TODO: add fast palindrome impl.
 ~~~clojure
-(define (fast-palindrome input ) ....)
+(define (fast-palindrome? input)
+  (cond
+   ((string-null? input) #t)
+   (else
+    (do ((i 0 (add1 i))
+         (j   (sub1 (string-length input)) (sub1 j)))
+        ((or (not (char=? (string-ref input i) (string-ref input j)))
+             (>= i j))
+         (<= j i))))))
+
 (test-generative ((str (gen-sample-of (gen-string-of (gen-char)) (gen-palindrome))))
   (test-assert (eq? (palindrome? str) (fast-palindrome? str))))
 ~~~
 This looks like a reasonable optimization. Let's see what our model based testing reveals:
 
 ~~~clojure
-(use test test-generative data-generators)
+ (use test test-generative data-generators)
 
-(test-generative ((x (gen-sample-of (gen-fixnum) (gen-flonum)))
-                  (y (gen-sample-of (gen-fixnum) (gen-flonum))))
-  (test-assert (= (* x y) (fast-* x y))))
+ (define (fast-* x y)
+   (cond
+    ((zero? x) x)
+    ((zero? y) y)
+    (else (* x y))))
+
+ (test-begin "fast-mul")
+
+ (test-generative ((x (gen-sample-of (gen-fixnum) (gen-flonum)))
+                   (y (gen-sample-of (gen-fixnum) (gen-flonum))))
+   (test-assert (= (* x y) (fast-* x y))))
+
+ (test-end "fast-mul")
+
+ (test-exit)
 ~~~
 
 Running these tests might show the following output:
 
 <pre>
+-- testing fast-mul ----------------------------------------------------------
+(= (* x y) (fast-* x y)) ............................................. [ <span style="color:red">FAIL</span>]
+    assertion failed
+    iteration: 6
+    seeds: ((x 0.821921655141171) (y +nan.0))
+1 test completed in 0.002 seconds.
+<span style="color:red">1 failure (100%).</span>
+0 out of 1 (0%) tests passed.
+-- done testing fast-mul -----------------------------------------------------
 </pre>
 
 Ohoh, as you can see our optimization isn't actually valid for flonums. The flonum generator
-also generated +nan.0 which is a special flonum that doesn't produce 0 when it is multiplied with 0. In fact this optimization is only valid for fixnums. Thanks to our automated tests we found out about that case and refuse to try to be smarter than core.
+also generated +nan.0 which is a special flonum that doesn't produce 0 when it is multiplied with 0. IEEE requires NaN to be propagated. In fact this optimization is only valid for fixnums. Thanks to our automated tests we found out about that case and will refuse to try to be smarter than core.
+
+There are more applications to these kinds of tests. They often serve as a good basis for a thorough test-suite. They're easy to build and quite reliable.
 
 ### Integrating tests into your Emacs workflow
 
-- chicken-test-mode
-- what does it give you
-- alternatives
-- run command
+You're still here? That's good. We're half way through already! I'm just kidding. This is the last section, in which I want to tell you about some ideas that allow you to integrate testing into your development workflow using our great Emacs editor.
+If you don't use Emacs, you won't gain much from this paragraph. In that case I'd like you
+to go on with the [Wrap up](#wrap-up).
+
+Having all the great tools to do your testing is valuable but you also want to have a way
+to integrate testing into your workflow. In particular you might want to be able to run
+your test-suite from within Emacs and work on the test results. I created a little extension
+for Emacs that aims to provide such an integration. It is currently work in progress but I use
+it regularily already. You can find **chicken-test-mode** [here](https://bitbucket.org/certainty/chicken-test-mode/overview).
+
+#### What does it give you?
+
+This mode is roughly divided into two parts. One part gives you functions that allow you to run your test-suite. The other part deals with the navigation within your test-output. Let us dive in and put the mode to practice. Suppose you have installed the mode according to the little help text that is in the header of the mode's source file.
+We further assume that we're working on the stack example from the beginning of this article. I have opened up a buffer that holds the scheme implemenantion file of the stack. We need to adjust the test file to load the implementation differently.
+
+~~~clojure
+ (use test)
+ (load-relative "../stack.scm")
+
+ ; .... tests follow
+~~~
+
+This enables us to run the tests from within emacs without problems.
+
+#### Running tests within Emacs
+
+With these definitions in place I can now issue the command **C-c t t** which will run the tests, open up the CHICKE-test buffer and put the output of your tests there. In my setup it looks like this:
+
+<a href="/assets/images/posts/testing_chicken/run-tests.png">
+  <img src="/assets/images/posts/testing_chicken/run-tests_thumb.png">
+</a>
+
+You can click on the image to load it fullsize. You see two buffers opened now. The buffer
+on the left side holds the application code and the buffer on the right side holds the output
+of the tests. What you can not see here is that there will be a minibuffer message telling you
+whether the tests have all passed or if there were failures.
+
+#### Navigating the test output
+
+You can now switch to the test buffer (C-x o). Inside that buffer you have various possibilities to navigate. Just hitting **S-p** will allow you to step through each test backwards.
+Hitting **S-n** will do the same thing but forward. Things get more interesting when there are failures. So let's quickly introduce some failures and see what we can do.
+
+~~~clojure
+(use test)
+(load-relative "../stack.scm")
+
+(test-begin "stack")
+
+(test-group "make-stack"
+ ; ... tests
+ )
+
+(test-group "stack-push!"
+ ; ... tests
+ )
+
+(test "this test shall fail" #t #f)
+
+(test-group "stack-top"
+ ; ... tests
+ )
+
+(test "this test shall fail too" #t #f)
+
+(test-end "stack")
+
+(test-exit)
+~~~
+
+As you can see I added two failing tests. When I run the tests again now, the buffer opens up and shows me the output that of course contains our errors.
+I change to the buffer **(C-x o)** and hit **f**. This will bring me to the **f**irst failing test. In my case it looks like this:
+
+
+<a href="/assets/images/posts/testing_chicken/run-tests-w-failures.png">
+  <img src="/assets/images/posts/testing_chicken/run-tests-w-failures_thumb.png">
+</a>
+
+The first failing tests has been selected and the line it accures in has been highlighted.
+You can jump straight to the next failed test by hitting **n** in the test buffer.
+Likewise you can hit **p** to jump to the **p**revious failing test. Lastly you can hit
+**l** to jump to the last failing test.
+If you're done you can just hit **q** to close the buffer.
+
+#### More possibilities to run tests
+
+Beside running the full test-suite you can also apply a filter an run only those tests that
+match the filter. Let's suppose that we only run the tests that contain the text "top-most element". In reality you might want to mark your tests specially as I have already described in the best practices section. To run tests filtered you can type **C-t f** which will ask you for the filter to apply. This looks like this:
+
+<a href="/assets/images/posts/testing_chicken/run-tests-w-filter.png">
+  <img src="/assets/images/posts/testing_chicken/run-tests-w-filter_thumb.png">
+</a>
+
+Mind the mini-buffer. It asks for the filter to use. Now once I hit enter I get the filtered results that look like this:
+
+
+<a href="/assets/images/posts/testing_chicken/run-tests-w-filter-apply.png">
+  <img src="/assets/images/posts/testing_chicken/run-tests-w-filter-apply_thumb.png">
+</a>
+
+There is a little bit more like removing tests and running filters on test-groups. Check out
+the project to learn about all its features. I'm currently thinking on how to implement a function that allows you to test the procedure under point. That would be relatively easy for tests
+that don't use description strings but use the short test form which will pretty print the expression. With that in place I could run a filtered tests that only includes tests that have the name of the procedure in them. It's not exactly elegant but it may work. In the mean time the things that are already there hopefully help.
 
 ### Wrap up
 
+Wow, you've made it through the text. It has been a long one, I know. I have hope that I did not bore you to death. You've learned alot about CHICKEN's test culture and the tools you have
+at your disposal to address your very own testing needs. I have hope that the information provided here serves as a good introduction to these tools. Please feel free to contact me if that's not the case or if things are just plain wrong.
 
 # References
 
 * [regression testing](https://en.wikipedia.org/wiki/Regression_testing)
 * [black swans](http://testingreflections.com/node/7584)
 * [ideas around bug clusters](http://www.developsense.com/blog/2009/01/ideas-around-bug-clusters)
+* [test](https://wiki.call-cc.org/eggref/4/test)
+* [test-generative](https://wiki.call-cc.org/eggref/4/test-generative)
+* [data-generators](https://wiki.call-cc.org/eggref/4/data-generators)
+* [chicken-test-mode](https://bitbucket.org/certainty/chicken-test-mode/overview)

File assets/images/posts/testing_chicken/run-tests-w-failures.png

  • Ignore whitespace
Added
New image

File assets/images/posts/testing_chicken/run-tests-w-failures_thumb.png

  • Ignore whitespace
Added
New image

File assets/images/posts/testing_chicken/run-tests-w-filter-apply.png

  • Ignore whitespace
Added
New image

File assets/images/posts/testing_chicken/run-tests-w-filter-apply_thumb.png

  • Ignore whitespace
Added
New image

File assets/images/posts/testing_chicken/run-tests-w-filter.png

  • Ignore whitespace
Added
New image

File assets/images/posts/testing_chicken/run-tests-w-filter_thumb.png

  • Ignore whitespace
Added
New image

File assets/images/posts/testing_chicken/run-tests.png

  • Ignore whitespace
Added
New image

File assets/images/posts/testing_chicken/run-tests_thumb.png

  • Ignore whitespace
Added
New image