Commits

Anonymous committed 06de8b7

began to polish up the text

  • Participants
  • Parent commits 902fb27

Comments (0)

Files changed (1)

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

 tags: [scheme,test,chicken,testing]
 ---
 
-Hello everybody and welcome back. In this article I attempt to introduce you to the very excellent [test egg](http://wiki.call-cc.org/eggref/4/test), which is a great way to do your unit-testing in CHICKEN.
+Hello everybody and welcome back. In this article I'll attempt to introduce you to the very excellent [test egg](http://wiki.call-cc.org/eggref/4/test), which is a great way to do your unit-testing in CHICKEN.
 
-It will start with a gentle introduction to unit testing in general, before we dive into the **test egg** itself. I'll show you a few **best practices** that will help you to benefit most from your test code. After I've outlined the bells and whistles that come with **test**, I'll introduce you to **random testing** on top of **test**. Finally I'll give you some hints on how a useful Emacs setup to do CHICKEN unit tests may look like.
+It will start with a gentle introduction to unit testing in general, before we dive into the **test egg** itself. I'll present you a few **best practices**, that will help you to benefit most from your test code. After I've outlined the bells and whistles that come with **test**, I'm going to introduce you to **random testing** on top of **test**. Finally you'll be given some hints on how a useful Emacs setup to do testing in CHICKEN may look like.
 
 You can either read this article as a whole, which is what I recommend, or cherry-pick the parts that you're interested in. Both will hopefully work out.
 
-For those of you who are fluent with **test**, there is probably not much new here. Still I'd love you to be my guest and read on. Don't hesitate to come back to me and tell me about things I've missed or things that you do differently that work great. I'm eager to learn about your setup.
+For those of you, who are fluent with **test**, there is probably not much new here. Still I'd love you to be my guest and read on. Don't hesitate to come back to me and tell me about things I've missed or things that you do differently. I'm eager to learn about your setup.
 
-But now without further ado, let's go down this rabbit hole.
+Now without further ado, let's go down this rabbit hole.
 
 ### A gentle introduction to testing
 
-You probably heard that testing your code is good practice and that every *serious* software engineer must do it. I do agree with this in general and most software engineers out there do as well. There are different schools though. Some do the tests after their code, some do them before and yet others do them while they flesh out their functions in the REPL. I don't want to tell you that there is only one true way to do it, but there are a few arguments that I'd like to make, that suggest that a particular school may have advantages. At first though, I want to give you a very brief overview
-of what testing gains you.
+You probably heard, that testing your code is good practice and that every *serious* software engineer is obliged to do it. I do agree with this in general and the software engineers I know, do as well. While there seems to be a general agreement that tests are good, there are also different schools of testing. Some do the tests after their code, some do them before and yet others do them while they flesh out their functions in the REPL. I don't want to tell you, that there is only one true way to do it, but there are a few arguments that I'd like to make, that suggest that a particular school may have advantages. At first though, I want to give you a very brief overview of what testing gains you.
 
 #### What does testing give you?
 
-If it is done right, it gives you a reasonable amount of confidence that the code you're testing works correctly. Your tests act like a specification for the code under test.
-Secondly they give you a safety net that enables you to change your code and still make sure that the code works as expected. This means that you're free to refactor your code without having to worry, that you broke some, probably distant, part of the code, while doing so. That also means that someone else, who wants to contribute to your code, which is a fact that must not be underestimated.
+If done right, it gives you a reasonable amount of confidence, that the code you're testing works correctly. Your tests act like a specification for the code under test.
+Secondly they give you a safety net that enables you to change your code and still make sure, that the code works as expected. This means that you're free to refactor your without having to worry, that you broke some, probably distant, part of the code. That is not only true for yourself but also for another person, who wants to contribute to your code.
 
-Closely related to this are regression tests, that are used to detect bugs that have been fixed but which now pop up again, after you have changed some portion of your code. Regression tests are an important part of a test suite. Once you discover a bug you generally write a test that reproduces it. This test will be naturally failing as the system/code under test doesn't behave as expected. The next step is to fix this bug and make the test pass. This way you have made sure that this particular bug has been fixed.
-This must be contrasted with the sort of tests you use to test your features. While those are
-estimates, testing for bugs and fixing them can act as a proof. Of course there is no rule without an exception. [Bugs tend to come in clusters](http://testingreflections.com/node/7584) and can be grouped into categories or families. This means in practice that you may have fixed this particular bug but you're advised to look
-for a generalization of that bug that might occur elsewhere. Also you likely want to check
-the code that surrounds the part that caused the bug. It has been shown empirically that it is
-likely to contain bugs as well. For a critical view on this theory you might want to have
-a look at [this](http://www.developsense.com/blog/2009/01/ideas-around-bug-clusters).
+Closely related to this are regression tests, which are used to detect bugs, that have been fixed sometime in the past, but pop up again, after you have changed some portion of your code. Regression tests are an important part of a test suite. Once you discover a bug, you generally write a test that reproduces it. This test will be naturally be failing as the system/code under test doesn't behave as expected. The next step is to fix the bug and make the test pass. This must be contrasted with the sort of tests that are used to test your features. While those are
+estimates for the correctness of your code, testing for bugs and fixing them can act as a proof. Of course there is no rule without an exception. [Bugs tend to come in clusters](http://testingreflections.com/node/7584) and can be grouped into categories or families. This means in practice that you may have fixed this particular bug but you're advised to look
+for a generalization of that bug, that might occur elsewhere. Also you likely want to check the code, that surrounds the section that caused that constitutes the bug. It has been shown empirically that it is likely to contain bugs as well. For a critical view on this theory, you might want to have a look at [this](http://www.developsense.com/blog/2009/01/ideas-around-bug-clusters).
 
-Also tests often are a form of documentation. They describe the expected behavior of your code and thus give strong hints about how it shall be used. Often you find that the documentation
-of a project isn't very well. If it at least has a thorough and good test-suite you can quickly learn the most important aspects of the library.
+Also tests often are a form of documentation. They describe the expected behavior of your code and thus give strong hints about how it shall be used. You may find that the documentation
+of a project isn't very well. If it at least has a thorough test-suite, you can quickly learn the most important aspects of the library.
 
 There are many more testing categories that all have their particular value. The literature is
-full of those and I very much recommend reading some of it. The [reference section](#references) has a few links
-that you may find useful.
+full of those and I very much recommend reading some of it. The [reference section](#references) has a few links, that you may find useful.
 
 #### What does testing not give you?
 
-Tests for features can never prove that your code doesn't contain bugs and is correct. It is only an estimation. You write as much tests as needed to reach a level of confidence that you need.
-This level may be either perceived intuitively or measured. A common way to measure it is a so called, code coverage analysis. This just means that an analyzer runs your tests and checks which code paths they exercise. The result may be used to derive a metric for the developer on when he/she has good enough tests. This approach has some flaws though and a 100% coverage says nothing about
+Tests for features can never prove that your code doesn't contain bugs. It is only an estimation. You write as much tests as needed to reach a level of confidence that you find sufficiant.
+This level may be either perceived intuitively or measured. A common way to measure it is the, so called, code coverage analysis. An analyzer runs your tests and checks which code paths they exercise. The result may be used to derive a metric for the developer on when he/she has good enough tests. This approach has some obvious flaws and a 100% coverage says nothing about
 the quality of your tests. You can easily see that you can have tests that execute all of your code paths but simply do not verify their outputs. In this case you have 100% coverage, but actually
-0 confidence that the code is correct.
+zero confidence that the code is correct.
 
-While code coverage gives you a qualitative measure of your test code there is also a quantitative measure. That is the code to test ratio. It's a simple as it can be, it just tells you the proportion of your code and tests. Most people tend to agree that a ratio of 1:2 is about good. That means you have twice as much tests as you've got actual code. In my opinion that very much depends on the kind of project. If you happen to have many internal helper procedures and very few procedures that belong to the public API, then you most likely won't reach that ratio. If your code is mostly public API though that it may be actually close to the truth. Each procedure is likely to have at least two tests. Again my advice is not to use that as an absolute measure but only as a guideline on to verify that you're on the right track.
+While code coverage gives you a qualitative measure of your test code there is also a quantitative measure. That is the code to test ratio. It's as simple as it can be; it just tells you the proportion of your code and tests. Most people tend to agree that a ratio of 1:2 is about good. That means you have twice as much tests as you've got actual code. In my opinion that very much depends on the kind of project. If you happen to have many internal helper procedures and very few procedures that belong to the public API, then you most likely won't reach that ratio. If your code is mostly public API though then it may be actually close to the truth as each procedure is likely to have at least two tests. Again my advice is not to use that as an absolute measure but only as a guideline to verify that you're on the right track.
 
-Let's resume after that little detour.
+Another aspect that must be emphasized is that tests can never prove the absence of bugs, possibly with the exception of regression tests. If tests have been written **after** a certain bug occured you have a high probability that this specific bug has been fixed. Apart from these though, tests are by no means a proof for the absence of bugs.
 
-Another aspect that must be emphasized is that tests can never prove the absence of bugs, possibly with the exception of regression tests. If tests have been written **after** a certain bug occur you have a high probability that this specific bug has been fixed. Apart from these though, there is by no means a proof that tests can give you of the correctness of your code.
-
-Tests are not a silver bullet and are not a replacement for good design and solid software engineering skills. Having great many tests that verify features of your application is comforting and all, but be assured that there will be a time when a bug pops up in your application. This means that all your tests didn't do anything to prevent this bug. You're on your own now.
+Tests are not a silver bullet and are not a replacement for good design and solid software engineering skills. Having great many tests that verify features of your application is comforting and all, but be assured that there will be a time when a bug pops up in your application. All your tests didn't do anything to prevent this bug. You're on your own now.
 Now you actually have to understand your system, reason about it and figure out what went wrong. This is another crucial part of developing
-an application. You must make sure that you have a system that you can actually understand and reason about. Tests can help to develop such a system, as it has been shown that software that is easy to test is often also [simpler](http://www.infoq.com/presentations/Simple-Made-Easy), more focused and easier to comprehend.
+an application. You must make sure that you have a system that you can actually understand. Tests can help to develop such a system, as it has been shown that software that is easy to test is often also [simpler](http://www.infoq.com/presentations/Simple-Made-Easy), more focused and easier to comprehend.
 
 #### If testing is that great, why do some people still don't do it?
 
 I can't give you a universal answer to this, as there is probably a great variety of reasons, which might or might not be sensible. I've heard some reasons repeatedly though.
 
-* **It is more work then just writing your application code**
+* **It is more work than just writing your application code**
 
-  This one is true. Writing tests is an investment. It does cost more time, more money, more energy  rgy etc. But as with all good investments, they better pay off in the end. It turns out that
-  most of the time this is indeed the case. The longer a project exists the more often you or someone else comes back to your code and changes it. This involves fixing bugs, adding new features, improving performance, you name it. For all those cases, you will spend significantly less time
+  This one is true. Writing tests is an investment. It does cost more time, more money and more energy. But as with all good investments, they probably pay off in the end. It turns out that
+  most of the time this is indeed the case. The longer a project exists, the more often you or someone else comes back to your code and changes it. This involves fixing bugs, adding new features, improving performance, you name it. For all those cases, you will spend significantly less time
   if you have a test-suite that helps you to ensure that all those changes didn't break anything.
 
 * **It's hard to break the thing that you just carefully built**
 
-  It's just not fun to try to destroy what you just build. Suppose you build a procedure that has
+  It's just not fun to try to destroy what you just built. Suppose you finished a procedure that has
   been really hard to accomplish. Now you're supposed to find a possible invocation in which it
-  misbehaves. If you succeed you will have to get back at it and fix it. Which will again be very hard eventually. There is an inner barrier, that subconsciously holds you back. I think we all   agree that having found this misbehavior is better than keeping it buried, but the back of your
-  mind, might see this slightly different, especially when it's Friday afternoon at 6pm.
+  misbehaves. If you succeed you will have to get back at it and fix it, which will again be very hard eventually. There is an inner barrier, that subconsciously holds you back. I think we all agree that having found this misbehavior is better than keeping it buried, but the back of our
+  mind might disagree, especially when it's Friday afternoon at 6pm.
 
 * **It's not fun**
 
   I don't agree with that one, but I have heard that many times. I think that is possibly the
   consequence of the points above. If you create a mindset where tests are actually part of your
   code and are first class citizens of your project, then I think tests are at least as fun as the
-  application code.
+  application code itself.
 
 Of course there may be many more reasons. Just take these as an excerpt.
 
-
 #### OK, I want to test. How do I do it?
 
-While there is value in doing manual testing in the REPL or by executing your application by hand, you really also want a suite of **automated tests**. Automated means in practice that you have written
-code that tests your application. You can run these tests and the result will tell you if and which tests have failed or passed. This makes your tests reproducible with minimum effort. You want to develop this test suite as you develop your application. If you test before your actual code or after is really up to you. There is one thing though that I want to point out. There is a general problem with tests, well a few of those but one is particularly important now: How do you make sure that your test code is correct? It doesn't make much sense to put trust in your code because
-of your shiny test-suite when the tests in there are incorrect. This means they pass but shouldn't or they don't pass but really should. While you could write tests for your tests, you may immediately see that this is a recursive problem and might lead to endless tests testing tests testing tests ....
+While there is value in doing manual testing in the REPL or by executing your application by hand, you really also want a suite of **automated tests**. Automated means in practice, that you have written code that tests your application. You can run these tests and the result will tell you if and which tests have failed or passed. This makes your tests reproducible with minimum effort. You want to develop this test suite as you develop your application. If you test before your actual code or after is really up to you. There is one thing though that I want to point out. There is a general problem with tests, well a few of those but one is particularly important now: **How do you make sure, that your test code is correct?** It doesn't make much sense to put trust in your code because
+of your shiny test-suite, when the test-suite itself is incorrect. Possible all tests pass where they shouldn't or they don't pass but really should. While you could write tests for your tests, you may immediately see that this is a recursive problem and might lead to endless tests testing tests testing tests ....
 
-This is one reason why doing tests before code might be helpful. This discipline is called [TDD](https://en.wikipedia.org/wiki/Test-driven_development). It suggests a work-flow that we refer to as **"Red-Green-Refactor"**. **Red** means that we start with a failing test. **Green** means that we implement as much of the application code, that is needed to make this test pass. **Refactor** is changing details of your code without effecting the overall functionality. I don't want to go into details but there is one aspect that is particularly useful. When we start with a **red test**, we at least
-have some good evidence that our tests test portions of our code that don't yet work as expected.
-We have some confidence that we're testing the right thing before we make the test pass.
-Contrast this with tests that you do after your code. You don't ever know if the tests would
-be failing in case the code didn't work correctly. You could update parts of your application code to emulate this, but that's often more work. This is what the TDD-folks consider good enough
-to make sure that the tests work correctly, so that they don't need a test-suite for a test-suite for a test-suite ....
+This is one reason why doing tests **before** code might be helpful. This discipline is called [TDD](https://en.wikipedia.org/wiki/Test-driven_development). It suggests a work-flow, that we refer to as **"Red-Green-Refactor"**. **Red** means that we start with a failing test. **Green** means that we implement as much of the application code, that is needed to make this test pass. **Refactor** is changing details of your code without effecting the overall functionality. I don't want to go into details, but there is one aspect that is particularly useful.
+If we start with a **red test**, we at least have some good evidence that our tests exercises portions of our code that don't yet work as expected, because otherwise the test would succeed. Also
+if there are no errors, we have some confidence that the test code is correct. Also we have trust that we're testing the right thing before we make the test pass.
+Contrast this with tests that you do after your code. You don't ever know if the tests would be failing in case the code didn't work correctly. You could update parts of your application code to emulate this, but that's often more work. This is what the TDD-folks consider good enough to make sure that the tests work correctly, so that they don't need a test-suite for a test-suite for a test-suite ....
 There are other aspects of TDD that I don't cover here, like responding to difficult tests by changing your application code instead of
 the tests. There is many more and I invite you to have a look at this methodology even if you don't apply it.
 Personally I do test before and I do test after and also while I develop application code. I try though to test first, if it's feasible.
 
-There are many best practices when it comes to testing. I can not name and explain all of them here. One reason is that I certainly don't know them all and the other is that there are to many that are very well explained elsewhere.
+There are many best practices when it comes to testing. I can not name and explain all of them here. One reason is that I certainly don't know them all and the other is that there are too many.
 A few of them are very essential though and I have often seen people violating them which made their tests brittle.
 
 **«Always think about the value of the tests»**
 
-Don't write tests just because someone said you must. Don't write tests that don't improve the trust in your system. This can be a difficult decision. Test code is code just like your application code. It has to be written and maintained.
+Don't write tests just because someone said you must. Don't write tests, that don't improve the trust in your system. This can be a difficult decision. Test code is code just like your application code. It has to be written and maintained.
 
 **«Think about interfaces not implementation»**
 
 
 Write enough test code to *"verify"* one aspect of your function but not more. For example if
 you have three invariants that you can test for a given function, then you likely want three tests for them. The reason may not be
-obvious but it should become clear in a moment. There should be only one reason for your tests to fail. The next step after you noticed a failing test is to find out
-what went wrong. If there are multiple possibilities why the test have failed because you verified three invariants in one test, you
-have to investigate all three paths. Having one test for each of the invariants makes this task trivial, you immediately see what the
-culprit is. The other aspect is that it tends to keep your test code small, which means that you have fewer code to maintain and
-fewer places you can be wrong in one test. The attentive reader might have noticed that a consequence from this guideline is, that you
-have more tests. This is totally true so you want to make sure that they execute fast. A typical test suite of unit-tests often contains
+obvious but it should become clear in a moment. **There should be only one reason for a test to fail**. This is because the step after you noticed a failing test is to find out
+what went wrong. If there are multiple possibilities why the test has failed, you have to investigate all paths.
+Having one test for each of the invariants makes this task trivial as you immediately see what the culprit is.
+The other aspect is, that it tends to keep your test code small, which means that you have fewer code to maintain and
+fewer places that can be wrong. The attentive reader might have noticed that a consequence from this guideline is, that you
+have more tests. This is totally true. You want to make sure that they execute fast then. A typical test-suite of unit-tests often contains
 a rather large amount of small tests.
 
 **«Keep your tests independent»**
 
-This just means that tests should be implemented in such a way that only the code inside the test you're looking at can make
-the test fail or pass. It must not depend on other tests. This is likely to occur when your code involves mutation of shared state.
-Suddenly you may find that your test only passes if you run the entire suite but fails if you run it in isolation. This is obviously a
-bad thing as it makes your tests unpredictable. One way to automatically detect these kinds of dependencies is to randomize the
+This just means that tests should be implemented in such a way that, only the code inside the test you're looking at can make
+the test fail or pass. In particular it must not depend on other tests. This is likely to occur when your code involves mutation of shared state.
+Suddenly you may find that your test only passes, if you run the entire suite but fails if you run on test in isolation. This is obviously a
+bad thing, as it makes your tests unpredictable. One way to automatically detect these kinds of dependencies is to randomize the
 order in which tests are executed. This is useful as sometimes you're simply not aware of one test depending on another.
 
 **«Keep your tests simple»**
+
 Naturally tests are a critical part of your system. They are the safety net. You don't want them to contain bugs. Keeping them simple also means that it is easier to make them correct. Secondly they are easier to comprehend. Test-code should state as clear as possible what it is supposed to do.
 
 
 **«Keep your tests fast»**
-This turns out to be a crucial feature of your test suite as well. If your tests are slow they will disrupt your work-flow. Ideally testing and writing code is smoothly intertwined. You test a little, then you code a little, then you repeat. If you have to wait for a long time for your tests to finish there will be some point where you don't run them regularly anymore. Of course you can trim down your test-suite to just the tests that are currently important, but after you've finished the implementation of a particular procedure you will likely want to run the entire suite.
 
-These are all just general guidelines that apply to unit-tests in general. There are specific Do and Don'ts that apply to other kinds
+This turns out to be a crucial feature of your test suite as well. If your tests are slow they will disrupt your work-flow. Ideally testing and writing code is smoothly intertwined. You test a little, then you code a little, then you repeat. If you have to wait for a long time for your tests to finish, there will be some point where you don't run them regularly anymore. Of course you can trim down your test-suite to just the tests that are currently important, but after you've finished the implementation of a particular procedure you will likely want to run the entire suite.
+
+These guidelines apply to unit-tests in general. There are specific Do and Don'ts that apply to other kinds
 of tests that I don't want to cover here. I hope this little introduction gave you enough information to go on with the rest of the article and you now have a firm grip of what I'm going to be talking about.
 
 ### Putting the test egg to work
 
-You're still here and not bored away by the little introduction. Very good since this is finally where the fun starts and we will be seeing actual code. CHICKEN is actually a good environment to do testing. Almost every egg is covered by unit tests and within the community there seems to be a general agreement that tests are useful. Additionally tests for CHICKEN extensions are encouraged particularly. We have a great continuous integration (CI) setup, that will automatically run the unit tests of your eggs, even on different platforms and CHICKENS. You can find more information on [tests.call-cc.org](http://tests.call-cc.org/). I'll tell you a little more about this later. For now just be assured that you're in good company.
+You're still here and not bored away by the little introduction. Very good, since this is finally where the fun starts and we will be seeing actual code. CHICKEN is actually a good environment to do testing. Almost every egg is covered by unit-tests and within the community there seems to be a general agreement, that tests are useful. Additionally tests for CHICKEN extensions are encouraged particularly. We have a great continuous integration (CI) setup, that will automatically run the unit-tests of your eggs, even on different platforms and CHICKENS. You can find more information on [tests.call-cc.org](http://tests.call-cc.org/). I'll tell you a little more about this later. For now just be assured that you're in good company.
 
-Let's continue our little journey now. We'll be implementing the well known [stack](https://en.wikipedia.org/wiki/Stack_(abstract_data_type) and build a suite of unit tests for it. This is a fairly simple task and allows us to concentrate on the tests. You can find all the code that is used here at:
+Let's continue our little journey now by implementing the well known [stack](https://en.wikipedia.org/wiki/Stack_(abstract_data_type) and building a suite of unit-tests for it. This is a fairly simple task and allows us to concentrate on the tests.
 
 #### Prerequisites
 
-You obviously need [CHICKEN](https://code.call-cc.org/) and you need the [test egg](https://wiki.call-cc.or/eggref/4/tess).
-You can obtain it with the lovely **chicken-install**. I assume you're familiar with it but I'll give you the command line anyway.
+You obviously need [CHICKEN](https://code.call-cc.org/) and you need the [test egg](https://wiki.call-cc.or/eggref/4/test).
+You can obtain it with the lovely **chicken-install**. I assume you're familiar with it, but I'll give you the command line anyway.
 
 ~~~ bash
  $ chicken-install test
 
 #### The project layout
 
-Once you've installed the test egg you can have a closer look at the directory layout of our example project.
-There is the top-level directory **stack** which holds one scheme source file named **stack.scm**. This is where your application code goes. Furthermore you'll notice that there is a directory called **tests** which holds a single file named **run.scm**. The entire layout looks like this:
+Once we've installed the test egg, we can have a closer look at the directory layout of our example project.
+There is the top-level directory **stack**, which holds one scheme source file named **stack.scm**. This is where our application code resides. Furthermore there is a directory called **tests** which holds a single file named **run.scm**. The entire layout looks like this:
 
 <pre>
  stack
 
 This is the standard layout of a scheme project for CHICKEN. There are projects that have additional folders
 and structure their files differently but the majority of projects look like this, so it is a good practice
-to follow it. You may noticed that this is also the standard layout of CHICKEN eggs. They contain egg specific files like *.release-info, *.meta and *.setup but apart from that, they look very much like this. Another reason to arrange your tests the way I showed you is that CHICKEN's CI at [salmonella](https://tests.call-cc.org) expects this layout. You can benefit from this service once you follow this convention. It's time to give **mario** and **peter** a big thank you, as they made it possible.
+to follow. You may have noticed, that this is also the standard layout of CHICKEN EGGS. They contain egg specific files like *.release-info, *.meta and *.setup, but apart from that, they look very much like this. Another reason to arrange your tests the way I showed you is that CHICKEN's CI at [salmonella](https://tests.call-cc.org) expects this layout. You can benefit from this service once you follow this convention. It's time to give **Mario** and **Peter** a big **"thank you!"**, as they made it possible.
 
 #### Basic layout of the test file
 
-Let's dive in now and start writing our first tests. For this purpose we're going to add a little skeleton to tests/run.scm, so that it looks like this.
+Let's dive in now and start writing our first tests. For this purpose we're going to add a little skeleton to tests/run.scm, that looks like this.
 
 ~~~ clojure
  (use test)
 
 This little snippet is a useful template for the tests you write. It loads and imports the test egg. It encloses your
 tests with a **(test-begin)** and **(test-end)** form. You will want to do this as **test** will print a summary for every
-test within these boundaries. This means that you get a summary of how many tests have passed and how many tests have failed
-at the end of test's output. This means that you can't miss a failing test that has flitted across the screen. I've been bit by
-that many times. Finally the last line in your test file should be **(test-exit)**. This will make your test process exit
-with a status code that indicates the status of your tests. If there have been any tests failing it will return with a non-zero
-status code, which can be passed as an argument to the procedure and defaults to one. Zero will be the status code if all tests have passed.
-
-
-
+test within these boundaries. It contains information about how many tests have passed and how many tests have failed. It prints that summary at the very bottom,
+so that you can't miss a failing test that has flitted across the screen. I've been bit by that many times.
+Finally the last line in our test file should be **(test-exit)**. This will make the test process exit
+with a status code that indicates the status of tests tests. If there have been any tests failing it will return with a non-zero
+status code, which can be passed as an argument to the procedure and defaults to 1. Zero will be the status code if all tests have passed.
 
 We'll start by adding the procedure that we obviously need at the beginning. We want a way to create an empty stack. I'll start with a test for it.
 
  **(test description expected expression)**
 
 It takes multiple arguments. The first argument is a description string that gives a hint about
-what this particular test attempts to verify. The next argument is the **expected value**. It can be any scheme value. The last argument is the scheme expression that shall be tested. It will be evaluated and compared with the **expected value**.
-This is actually the long form. You can get by with the shorter form that omits the description string like so:
+what this particular test attempts to verify. The next argument is the **expected value**. It can be any scheme value. The last argument is the scheme expression, that shall be tested. It will be evaluated and compared with the **expected value**.
+This is actually the long form of the test macro. You can get by with the shorter form that omits the description string like so:
 
 ~~~ clojure
  (test 3 (+ 1 2))
 ~~~
 
-This is very handy for multiple reasons. The most obvious reason is that you don't have to think of a fitting description.
+That is very handy for multiple reasons. The most obvious reason is that you don't have to think of a fitting description.
 The test egg is smart enough to use a pretty-printed form of the expression, which is (+ 1 2) in our little example, as the
 description. Secondly you can use this feature to generate descriptions out of your expression that are still meaningful.
 You just have to create a form that reads nicely. Let me clarify this:
  (test #t (member 3 (list 1 2 3)))
 ~~~
 
-This will generate a description like this when you run the tests.
+This will generate a description like this, which makes the purpose of the tests pretty clear.
 
 <pre>
 (member 3 (list 2 3 4)) .............................................. [<span style="color:green"> PASS</span>]
 
 
 OK, going back to the example above. I've added a little test that attempts to verify
-that a stack that has been created with make-stack is initially empty.
+that a stack created with make-stack is initially empty.
 Let's run the tests now. You can do this by changing into the tests directory and running
 the file with csi.
 
 The output looks like this:
 
 <pre>
+-- testing stack -------------------------------------------------------------
 make-stack creates an empty stack .................................... [<span style="color:red">ERROR</span>]
 
 Error: unbound variable: stack-empty?
 -- done testing stack --------------------------------------------------------
 </pre>
 
-As you can see the test output indicates that something went wrong. There red ERROR clearly indicates this. The text following it shows the details that make things clearer. It tells us that
+As you can see the test output indicates that something went wrong. There red **ERROR** clearly indicates this. This is test's way to tell us that a condition has been signaled.
+The text following it shows the details, that make things clearer. It tells us that
 we attempted to use procedure that doesn't actually exist. This makes perfect sense since we didn't write any code yet. That's easy enough to mitigate.
 
 ~~~ clojure
-(define-record-type stack (create-stack elements) stack? (elements stack-elements stack-elements-set!))
-(define (stack-empty? stack) #t)
-(define (make-stack . elements) (create-stack (reverse elements))
+ (define-record-type stack (create-stack elements) stack? (elements stack-elements stack-elements-set!))
+ (define (stack-empty? stack) #t)
+ (define (make-stack . elements) (create-stack (reverse elements))
 ~~~
 
-I've added the minimal amount of procedures that are needed to remove the error eventually.
+I've added the minimal amount of procedures, that are needed to remove the error eventually.
 Please note that I've chosen to represent the stack as a list internally.
 
 <pre>
 </pre>
 
 This looks better. You can see that all tests we've written are now passing, as indicated by the green PASS on the right side. We've written enough code to make the tests pass, but it's easy to
-see that these tests are lying. stack-empty? always returns #t regardless of the content of a given stack. So let's add a test that verifies that a non-empty stack is indeed not empty. Our make-stack procedure allows us to specify initial elements of the stack so we have all we need to create our tests.
+see, that these tests are lying. The procedure (stack-empty?) always returns #t regardless of the argument. Let's add a test that verifies that a non-empty stack is indeed not empty. Our make-stack procedure allows us to specify initial elements of the stack so we have all we need to create our tests.
 
 ~~~ clojure
-(use test)
-(load "../stack.scm")
+ (use test)
+ (load "../stack.scm")
 
-(test-begin "stack")
-(test "make-stack creates an empty stack"
-   #t
-   (stack-empty? (make-stack)))
+ (test-begin "stack")
+ (test "make-stack creates an empty stack"
+    #t
+    (stack-empty? (make-stack)))
 
-(test "make-stack with arguments creates a non-empty stack"
-   #f
-   (stack-empty? (make-stack 'one 'two)))
+ (test "make-stack with arguments creates a non-empty stack"
+    #f
+    (stack-empty? (make-stack 'one 'two)))
 
-(test-end "stack")
+ (test-end "stack")
 
-(test-exit)
+ (test-exit)
 ~~~
 
 Running these tests reveals the following:
 -- done testing stack --------------------------------------------------------
 </pre>
 
-The output tells us that one of our tests has passed and one has failed. The red FAIL indicates that an assertion didn't hold. I this case stack-empty? returned #t for the non-empty stack. This is expected as stack-empty? doesn't do anything useful yet. This is the last possible result-type of a test. Contrast a FAIL with ERROR please. ERROR indicates that a condition has been signaled whereas FAIL indicates that an assertion did not hold.
+This time the output tells us that one of our tests has passed and one has failed. The red **FAIL** indicates that an assertion didn't hold. I this case (stack-empty?) returned #t for the non-empty stack. This is expected as (stack-empty?) doesn't do anything useful yet. That shows the last possible result-type of a test. Please take a second and contrast a FAIL with an ERROR. ERROR indicates that a condition has been signaled whereas FAIL indicates that an assertion did not hold.
 Let's quickly fix this and make all tests pass. stack.scm now looks like this:
 
 ~~~clojure
-(define-record-type stack (create-stack elements) stack? (elements stack-elements stack-elements-set!))
-(define (stack-empty? stack) (null? (stack-elements stack)))
-(define (make-stack . elements) (create-stack (reverse elements)))
+ (define-record-type stack (create-stack elements) stack? (elements stack-elements stack-elements-set!))
+ (define (stack-empty? stack) (null? (stack-elements stack)))
+ (define (make-stack . elements) (create-stack (reverse elements)))
 ~~~
 
 Running the tests for these definitions results in the following output:
 -- done testing stack --------------------------------------------------------
 </pre>
 
-Very good all tests are passing. We're in the green. Let's take the opportunity and refactor the test-code a bit. The first test asserts that the outcome of the procedure invocation is the boolean #t. Whenever you find yourself writing tests that look like **(test description #t code)**, then you might want to take the shorter **(test-assert)** form. Let's quickly do this in the test file.
+Very good! All tests are passing. We're in the green. Let's take the opportunity and refactor the test-code a bit. The first test asserts that the outcome of the procedure invocation is the boolean #t. Whenever you find yourself writing tests that look like **(test description #t code)**, then you might want to take the shorter **(test-assert)** form. It allows you to declare invariants of your procedures. Let's quickly do this in the test file.
 
 ~~~clojure
-(use test)
-(load "../stack.scm")
+ (use test)
+ (load "../stack.scm")
 
-(test-begin "stack")
+ (test-begin "stack")
 
-(test-assert "make-stack creates an empty stack"
-   (stack-empty? (make-stack)))
+ (test-assert "make-stack creates an empty stack"
+    (stack-empty? (make-stack)))
 
-(test "make-stack with arguments creates a non-empty stack"
-   #f
-   (stack-empty? (make-stack 'one 'two)))
+ (test "make-stack with arguments creates a non-empty stack"
+    #f
+    (stack-empty? (make-stack 'one 'two)))
 
-(test-end "stack")
+ (test-end "stack")
 
-(test-exit)
+ (test-exit)
 ~~~
 
-That reads a bit nicer. As every good refactoring, this one didn't change the semantic of our tests and consequently it didn't change the output that is generated, so I leave it out right now.
-
-There are some more procedures that are needed to make the stack actually useful. Let's continue by implementing **push** which will allow us to add a single value to the stack.
+That reads a bit nicer. As every good refactoring, this one didn't change the semantic of our tests and consequently it didn't change the output that is generated, so I leave that out right now.
+There are some more procedures, that are needed to make the stack actually useful. Let's continue by implementing **stack-push!**, which will allow us to add a single value to the stack.
 
 ~~~clojure
-(use test)
-(load "../stack.scm")
+ (use test)
+ (load "../stack.scm")
 
-(test-begin "stack")
+ (test-begin "stack")
 
-(test-assert "make-stack creates an empty stack"
-   (stack-empty? (make-stack)))
+ (test-assert "make-stack creates an empty stack"
+    (stack-empty? (make-stack)))
 
-(test "make-stack with arguments creates a non-empty stack"
-   #f
-   (stack-empty? (make-stack '(one two))))
+ (test "make-stack with arguments creates a non-empty stack"
+    #f
+    (stack-empty? (make-stack '(one two))))
 
-(test-group "stack-push!"
-  (test #f (stack-empty? (stack-push! (make-stack) 'item))))
+ (test-group "stack-push!"
+   (test #f (stack-empty? (stack-push! (make-stack) 'item))))
 
-(test-end "stack")
+ (test-end "stack")
 
-(test-exit)
+ (test-exit)
 ~~~
 
-You'll notice that I not only added a new test for **stack-push** but also introduced the form (test-group) which you don't know yet. This form allows you to group related tests into a named context. Every group runs the tests it contains and finishes them with a status report that tells you how many of the tests have failed and haw many have passed etc. I've added the group "stack-push" that will hold all tests that are needed to cover the stack-push procedure. While we're at it let's also create a group for make-stack. The test file now looks like this:
+You'll notice that I not only added a new test for **stack-push!** but also introduced the a now form: **(test-group)**. This form allows you to group related tests into a named context. Every group runs the tests it contains and finishes them with a status report, that tells you how many of the tests have failed and haw many have passed. I've added the group "stack-push!" that will hold all tests that are needed to cover the stack-push! procedure. While we're at it let's also create a group for make-stack. The test file now looks like this:
 
 ~~~clojure
-(use test)
-(load "../stack.scm")
+ (use test)
+ (load "../stack.scm")
 
-(test-begin "stack")
+ (test-begin "stack")
 
-(test-group "make-stack"
-  (test-assert "without arguments creates an empty stack"
-     (stack-empty? (make-stack)))
+ (test-group "make-stack"
+   (test-assert "without arguments creates an empty stack"
+      (stack-empty? (make-stack)))
 
-  (test "with arguments creates a non-empty stack"
-     #f
-     (stack-empty? (make-stack '(one two)))))
+   (test "with arguments creates a non-empty stack"
+      #f
+      (stack-empty? (make-stack '(one two)))))
 
-(test-group "stack-push!"
-  (test #f (stack-empty? (stack-push! (make-stack) 'item))))
+ (test-group "stack-push!"
+   (test #f (stack-empty? (stack-push! (make-stack) 'item))))
 
-(test-end "stack")
+ (test-end "stack")
 
-(test-exit)
+ (test-exit)
 ~~~
 
 The output that is generated reads like this:
 ~~~
 
 With these definitions all of our tests pass and we're back in the green. I'll fast forward now and show you the code and the tests that cover a little bit more of the API.
-The test file now looks like this:
 
 ~~~clojure
  (use test)
  (test-exit)
 ~~~
 
-The code look like this now:
+The code look like this:
 
 ~~~clojure
-(define-record-type stack (create-stack elements) stack? (elements stack-elements stack-elements-set!))
-(define (stack-empty? stack) (null? (stack-elements stack)))
-(define (make-stack . elements) (create-stack (reverse elements)))
+ (define-record-type stack (create-stack elements) stack? (elements stack-elements stack-elements-set!))
+ (define (stack-empty? stack) (null? (stack-elements stack)))
+ (define (make-stack . elements) (create-stack (reverse elements)))
 
-(define (stack-push! stack item)
- (stack-elements-set! stack (cons item (stack-elements stack)))
- stack)
+ (define (stack-push! stack item)
+  (stack-elements-set! stack (cons item (stack-elements stack)))
+  stack)
 
-(define (stack-top stack)
-  (car (stack-elements stack)))
+ (define (stack-top stack)
+   (car (stack-elements stack)))
 ~~~
 
-These tests all pass so far and we've added a few more tests for the stack-top API.
-Let's take a closer look at that procedure. It behaves well when the stack is non-empty, but what should happen if the stack is empty? Let's just signal a condition that indicates that taking
-the top item of an empty stack is an error. The test egg gives us another form that allows
-us to assert that a condition has been signaled. Let's see what this looks like.
+We've added a few more tests for the **stack-top** API. Let's take a closer look at that procedure. It behaves well when the stack is non-empty, but what should happen if the stack is empty? Let's just signal a condition, that indicates that taking the top item of an empty stack is an error. The test egg gives us another form that allows
+us to assert that we expect some piece of code to signal a condition. This form is **(test-error)**. Let's see what this looks like.
 
 ~~~clojure
-(use test)
-(load "../stack.scm")
+ (use test)
+ (load "../stack.scm")
 
-(test-begin "stack")
+ (test-begin "stack")
 
-(test-group "make-stack"
-  (test-assert "without arguments creates an empty stack"
-     (stack-empty? (make-stack)))
+ (test-group "make-stack"
+   (test-assert "without arguments creates an empty stack"
+      (stack-empty? (make-stack)))
 
-  (test "with arguments creates a non-empty stack"
-     #f
-     (stack-empty? (make-stack '(one two)))))
+   (test "with arguments creates a non-empty stack"
+      #f
+      (stack-empty? (make-stack '(one two)))))
 
-(test-group "stack-push!"
-  (test #f (stack-empty? (stack-push! (make-stack) 'item)))
-  (test "pushing an item makes it the new top item"
+ (test-group "stack-push!"
+   (test #f (stack-empty? (stack-push! (make-stack) 'item)))
+   (test "pushing an item makes it the new top item"
+       'two
+        (let ((stack (make-stack 'one)))
+          (stack-top (stack-push! stack 'two)))))
+
+ (test-group "stack-top"
+   (test "returns the only element for a stack with one element"
+      'one
+      (let ((stack (make-stack 'one)))
+        (stack-top stack)))
+   (test "returns the top-most element"
       'two
-       (let ((stack (make-stack 'one)))
-         (stack-top (stack-push! stack 'two)))))
+      (let ((stack (make-stack 'one 'two)))
+        (stack-top stack)))
+   (test-error "taking the top item from an empty stack is an error"
+      (stack-top (make-stack))))
 
-(test-group "stack-top"
-  (test "returns the only element for a stack with one element"
-     'one
-     (let ((stack (make-stack 'one)))
-       (stack-top stack)))
-  (test "returns the top-most element"
-     'two
-     (let ((stack (make-stack 'one 'two)))
-       (stack-top stack)))
-  (test-error "taking the top item from an empty stack is an error"
-     (stack-top (make-stack))))
+ (test-end "stack")
 
-(test-end "stack")
-
-(test-exit)
+ (test-exit)
 ~~~
 
-The last test in the test-group "stack-pop" attempts codify our assertion. Let's see
-what the output of this looks like. Instead of just invoking the tests normally like we did before I want to show you another feature of **test** that comes in handy. As we're currently
-working on the implementation of **stack-pop** we're currently not interested in the result of the other tests and would like to omit them. We can do so by applying a test filter. Take a look:
+The last test in the test-group "stack-top" attempts to codify our assertion. Let's have a look at the output.
+Instead of just invoking the tests normally, like we did before, I want to show you another feature of **test** that comes in handy. As we're currently
+working on the implementation of **stack-top** we're not interested in the result of the other tests and would like to leave them out.
+We can do so by applying a test filter. Take a look:
 
 <pre>
 TEST_FILTER="empty stack is an error" csi -s run.scm
 </pre>
 
-This will only run the tests which include the given text their description. This can actually be a regular expression, so it is much more versatile than it appears now. There is also the variable TEST_GROUP_FILTER which allows you to run only test-groups that match the filter. However in the current implementation of tests it seems not to be possible to filter groups within other groups. So setting TEST_GROUP_FILTER="stack-top" doesn't currently work. It will not run any tests since the filter doesn't match the surrounding group "stack". It would be a nice addition though.
+This will only run the tests which include the given text in their description. The filter can actually be a regular expression, so it is much more versatile than it appears at first. There is also the variable TEST_GROUP_FILTER which allows you to run test-groups that match the filter. However in the current implementation of test, it is not to be possible to filter groups within other groups. So setting TEST_GROUP_FILTER="stack-top" doesn't currently work. It will not run any tests since the filter doesn't match the surrounding group "stack". It would be a nice addition though.
 
 The output with the filter expression looks like this:
 
 </pre>
 
 **Please pay close attention to the output.** The test passes!
-How can that be? We didn't even implement the part of the code yet that signals an error in the case of an empty stack. This is a good example why it is good to write your tests first. If we had written the code after we would've never noticed that the tests succeed even without the proper implementation, which pretty much renders this particular test useless. It does more harm than good because it lies to you. This test passes because it is an error to take the **car** of the empty list. Obviously just checking that an error occurred is not enough. We should verify that a particular error has occurred. The test library doesn't provide a procedure or macro that does this so we have to come up with our own. We need a way to tell if and which condition has been signaled in a given expression. For this purpose I'll add a little helper to the very top
+How can that be? We didn't even implement the part of the code which signals an error in the case of an empty stack.
+This is a good example of why it is good practice to write your tests **before** your code. If we had written the tests after the code, we would've never noticed that the tests succeed even without the proper implementation, which pretty much renders these tests useless. The test passes already because it is an error to take the **car** of the empty list. Obviously just checking, that an error occurred is not enough. We should verify, that a particular error has been raised. The test library doesn't provide a procedure or macro that does this, which means we have to come up with our own. We need a way to tell if and which condition has been signaled in a given expression. For this purpose we'll add a little helper to the very top
 of the test file and update the tests to use that little helper.
 
 ~~~ clojure
  (use test)
-(load "../stack.scm")
+ (load "../stack.scm")
 
-(define-syntax condition-of
-  (syntax-rules ()
-    ((_ code)
-     (begin
-       (or (handle-exceptions exn (map car (condition->list exn)) code #f)
-           '())))))
+ (define-syntax condition-of
+   (syntax-rules ()
+     ((_ code)
+      (begin
+        (or (handle-exceptions exn (map car (condition->list exn)) code #f)
+            '())))))
 
-(test-begin "stack")
+ (test-begin "stack")
 
-; ... other tests
+ ; ... other tests
 
-(test-group "stack-top"
-  (test "returns the only element for a stack with one element"
-     'one
-     (let ((stack (make-stack 'one)))
-       (stack-top stack)))
-  (test "returns thet top-most element"
-     'two
-     (let ((stack (make-stack 'one 'two)))
-       (stack-top stack)))
-  (test "taking the top item from an empty stack is an error"
-     '(exn stack empty)
-      (condition-of (stack-top (make-stack)))))
+ (test-group "stack-top"
+   (test "returns the only element for a stack with one element"
+      'one
+      (let ((stack (make-stack 'one)))
+        (stack-top stack)))
+   (test "returns thet top-most element"
+      'two
+      (let ((stack (make-stack 'one 'two)))
+        (stack-top stack)))
+   (test "taking the top item from an empty stack is an error"
+      '(exn stack empty)
+       (condition-of (stack-top (make-stack)))))
 
-(test-end "stack")
+ (test-end "stack")
 
-(test-exit)
+ (test-exit)
 ~~~
 
-With these definitions, let's see now if our tests fail. Running the tests reveals:
+With these definitions, let's see now if our tests fail. Running them reveals:
 
 <pre>
 -- testing stack -------------------------------------------------------------
 Aha! We have a failing test saying that we were expecting a condition of type **(exn stack empty)** but we actually got a condition of type **(exn type)**. Now we can go on and add the code that signals the correct condition.
 
 ~~~clojure
-(define-record-type stack (create-stack elements) stack? (elements stack-elements stack-elements-set!))
-(define (stack-empty? stack) (null? (stack-elements stack)))
-(define (make-stack . elements) (create-stack (reverse elements)))
+ (define-record-type stack (create-stack elements) stack? (elements stack-elements stack-elements-set!))
+ (define (stack-empty? stack) (null? (stack-elements stack)))
+ (define (make-stack . elements) (create-stack (reverse elements)))
 
-(define (stack-push! stack item)
- (stack-elements-set! stack (cons item (stack-elements stack)))
- stack)
+ (define (stack-push! stack item)
+  (stack-elements-set! stack (cons item (stack-elements stack)))
+  stack)
 
-(define (assert-not-empty stack message)
-  (if (null? (stack-elements stack))
-    (signal
-     (make-composite-condition
-      (make-property-condition
-       'exn
-       'message message)
-      (make-property-condition 'stack)
-      (make-property-condition 'empty)))))
+ (define (assert-not-empty stack message)
+   (if (null? (stack-elements stack))
+     (signal
+      (make-composite-condition
+       (make-property-condition
+        'exn
+        'message message)
+       (make-property-condition 'stack)
+       (make-property-condition 'empty)))))
 
-(define (stack-top stack)
-  (assert-not-empty stack "can't take top of empty stack")
-  (car (stack-elements stack)))
+ (define (stack-top stack)
+   (assert-not-empty stack "can't take top of empty stack")
+   (car (stack-elements stack)))
 ~~~
 
 This little helper signals an error if someone tries to retrieve the top item of an empty stack.
-The output is as expected now:
+The test output look like this:
 
 <pre>
 -- testing stack -------------------------------------------------------------
 
 
 This looks very good. We have added tests for this case and while doing so we introduced a nice little helper to handle
-specific kinds of conditions. This is the usual way to do it. The test egg provides us with all the primitives that are needed
-to build on. It does not attempt to solve every possible problem for us. This is very much in the spirit of scheme and the [prime clingerism](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.154.5197) (Greetings to Peter).
+specific kinds of conditions. That's the usual way to do it. The test egg provides us with all the primitives that are needed
+to build on. It does not attempt to solve every possible problem. This is very much in the spirit of scheme and the [prime clingerism](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.154.5197) (Greetings to Peter).
 The next step is to run the entire test suite and check if still all other tests pass. I'll leave that out now but be assured that they all pass.
-You have learned now most of the things that are needed to use the test egg for your own code. I want to finish this part now and tell you something about the few bells and whistles that the test offers you.
+You have learned now most of the things that are needed to use the test egg for your own code. I want to finish this part and tell you something about the bells and whistles that test offers you.
 
 ### Bells and whistles of the test egg