testing: More restructuring for the Nose source
[swc-testing-nose.git] / testing / nose / instructor.md
index 1923ea8097c2923bf466387b9b227c0e0e5ef6d6..a5068ffb840038d75cb5b6e63dcf5fd91d52b219 100644 (file)
-# Mean-calculation example
+# Test locations
 
-* Basic implementation: [mean.py][basic-mean]
-* Internal exception catching: [mean.py][exception-mean]
-* Embedded tests: [mean.py][embedded-test-mean]
-* Independent tests: [test_mean.py][test-mean]
-
-# When should we test?
-
-Short answers:
-
--   **ALWAYS!**
--   **EARLY!**
--   **OFTEN!**
-
-Long answers:
-
-* Definitely before you do something important with your software
-  (e.g. publishing data generated by your program, launching a
-  satellite that depends on your software, …).
-* Before and after adding something new, to avoid accidental breakage.
-* To help remember ([TDD][]: define) what your code actually does.
-
-# Who should test?
-
-* Write tests for the stuff you code, to convince your collaborators
-  that it works.
-* Write tests for the stuff others code, to convince yourself that it
-  works (and will continue to work).
-
-Professionals often test their code, and take pride in test coverage,
-the percent of their functions that they feel confident are
-comprehensively tested.
-
-# How are tests written?
-
-The type of tests that are written is determined by the testing
-framework you adopt. Don't worry, there are a lot of choices.
-
-## Types of Tests
-
-**Exceptions:** Exceptions can be thought of as type of runtime test.
-They alert the user to exceptional behavior in the code. Often,
-exceptions are related to functions that depend on input that is unknown
-at compile time. Checks that occur within the code to handle exceptional
-behavior that results from this type of input are called Exceptions.
-
-**Unit Tests:** Unit tests are a type of test which test the fundamental
-units of a program's functionality. Often, this is on the class or
-function level of detail. However what defines a *code unit* is not
-formally defined.
-
-To test functions and classes, the interfaces (API) - rather than the
-implementation - should be tested. Treating the implementation as a
-black box, we can probe the expected behavior with boundary cases for
-the inputs.
-
-**System Tests:** System level tests are intended to test the code as a
-whole. As opposed to unit tests, system tests ask for the behavior as a
-whole. This sort of testing involves comparison with other validated
-codes, analytical solutions, etc.
-
-**Regression Tests:** A regression test ensures that new code does
-change anything. If you change the default answer, for example, or add a
-new question, you'll need to make sure that missing entries are still
-found and fixed.
-
-**Integration Tests:** Integration tests query the ability of the code
-to integrate well with the system configuration and third party
-libraries and modules. This type of test is essential for codes that
-depend on libraries which might be updated independently of your code or
-when your code might be used by a number of users who may have various
-versions of libraries.
-
-**Test Suites:** Putting a series of unit tests into a collection of
-modules creates, a test suite. Typically the suite as a whole is
-executed (rather than each test individually) when verifying that the
-code base still functions after changes have been made.
-
-# Elements of a Test
-
-**Behavior:** The behavior you want to test. For example, you might want
-to test the fun() function.
-
-**Expected Result:** This might be a single number, a range of numbers,
-a new fully defined object, a system state, an exception, etc. When we
-run the fun() function, we expect to generate some fun. If we don't
-generate any fun, the fun() function should fail its test.
-Alternatively, if it does create some fun, the fun() function should
-pass this test. The the expected result should known *a priori*. For
-numerical functions, this is result is ideally analytically determined
-even if the function being tested isn't.
-
-**Assertions:** Require that some conditional be true. If the
-conditional is false, the test fails.
-
-**Fixtures:** Sometimes you have to do some legwork to create the
-objects that are necessary to run one or many tests. These objects are
-called fixtures as they are not really part of the test themselves but
-rather involve getting the computer into the appropriate state.
-
-For example, since fun varies a lot between people, the fun() function
-is a method of the Person class. In order to check the fun function,
-then, we need to create an appropriate Person object on which to run
-fun().
-
-**Setup and teardown:** Creating fixtures is often done in a call to a
-setup function. Deleting them and other cleanup is done in a teardown
-function.
-
-**The Big Picture:** Putting all this together, the testing algorithm is
-often:
-
-```python
-setup()
-test()
-teardown()
-```
-
-But, sometimes it's the case that your tests change the fixtures. If so,
-it's better for the setup() and teardown() functions to occur on either
-side of each test. In that case, the testing algorithm should be:
-
-```python
-setup()
-test1()
-teardown()
-
-setup()
-test2()
-teardown()
-
-setup()
-test3()
-teardown()
-```
+Nose [looks in the usual places][finding-tests].
 
-* * * * *
+* Nose tests live in files matching `[Tt]est[-_]`
+* Nose can find `unittest.TestCase` subclasses.
+* Nose also finds functions matching the `testMatch` regular
+  expression.
 
-# Nose: A Python Testing Framework
+# Test syntax
 
-The testing framework we'll discuss today is called nose. However, there
-are several other testing frameworks available in most language. Most
-notably there is [JUnit](http://www.junit.org/) in Java which can
-arguably attributed to inventing the testing framework.
-
-## Where do nose tests live?
-
-Nose tests are files that begin with `Test-`, `Test_`, `test-`, or
-`test_`. Specifically, these satisfy the testMatch regular expression
-`[Tt]est[-_]`. (You can also teach nose to find tests by declaring them
-in the unittest.TestCase subclasses chat you create in your code. You
-can also create test functions which are not unittest.TestCase
-subclasses if they are named with the configured testMatch regular
-expression.)
-
-## Nose Test Syntax
-
-To write a nose test, we make assertions.
+Nose tests use assertions
 
 ```python
 assert should_be_true()
 assert not should_not_be_true()
 ```
 
-Additionally, nose itself defines number of assert functions which can
-be used to test more specific aspects of the code base.
-
-```python
-from nose.tools import *
-
-assert_equal(a, b)
-assert_almost_equal(a, b)
-assert_true(a)
-assert_false(a)
-assert_raises(exception, func, *args, **kwargs)
-assert_is_instance(a, b)
-# and many more!
-```
-
-Moreover, numpy offers similar testing functions for arrays:
-
-```python
-from numpy.testing import *
-
-assert_array_equal(a, b)
-assert_array_almost_equal(a, b)
-# etc.
-```
-
-## Exercise: Writing tests for mean()
-
-There are a few tests for the mean() function that we listed in this
-lesson. What are some tests that should fail? Add at least three test
-cases to this set. Edit the `test_mean.py` file which tests the mean()
-function in `mean.py`.
-
-*Hint:* Think about what form your input could take and what you should
-do to handle it. Also, think about the type of the elements in the list.
-What should be done if you pass a list of integers? What if you pass a
-list of strings?
+There are lots of assertion helpers in `nose.tools`
+([docs][nose-assertions]), which [exports][nose-assertion-export] the
+[unittest assertions][unittest-assertions] in [PEP 8][pep8] syntax
+(`assert_equal` rather than `assertEqual`).  There are more assertion
+helpers in `numpy.testing` ([docs][NumPy-assertions]) for arrays and
+numerical comparisons.
 
-**Example**:
+# Basic nose
 
-    nosetests test_mean.py
+Writing tests for `mean()`:
 
-# Test Driven Development
-
-Test driven development (TDD) is a philosophy whereby the developer
-creates code by **writing the tests first**. That is to say you write the
-tests *before* writing the associated code!
-
-This is an iterative process whereby you write a test then write the
-minimum amount code to make the test pass. If a new feature is needed,
-another test is written and the code is expanded to meet this new use
-case. This continues until the code does what is needed.
-
-TDD operates on the YAGNI principle (You Ain't Gonna Need It). People
-who diligently follow TDD swear by its effectiveness. This development
-style was put forth most strongly by [Kent Beck in
-2002](http://www.amazon.com/Test-Driven-Development-By-Example/dp/0321146530).
+* Basic implementation: [mean.py][basic-mean]
+* Internal exception catching: [mean.py][exception-mean]
+* Embedded tests: [mean.py][embedded-test-mean]
+* Independent tests: [test_mean.py][test-mean]
 
-For an example of TDD, see [the Fibonacci example][fibonacci].
+# Test-driven development
 
-# Quality Assurance Exercise
+We have [a Fibonacci example][fibonacci] with a series of increasingly
+detailed tests and implementations.
 
-Can you think of other tests to make for the fibonacci function? I promise there 
-are at least two. 
+# Quality assurance
 
-Implement one new test in test_fib.py, run nosetests, and if it fails, implement 
-a more robust function for that case.
+Can you think of other tests to make for the Fibonacci function?  I
+promise there are at least two.
 
-And thus - finally - we have a robust function together with working
-tests!
+Implement one new test in `test_fibonacci.py`, run `nosetests`, and if
+it fails, implement a more robust function for that case.
 
 
+[finding-tests]: https://nose.readthedocs.org/en/latest/finding_tests.html
+[nose-assertions]: https://nose.readthedocs.org/en/latest/testing_tools.html#testing-tools
+[nose-assertion-export]: https://github.com/nose-devs/nose/blob/master/nose/tools/trivial.py#L33
+[unittest-assertions]: http://docs.python.org/2/library/unittest.html#assert-methods
+[pep8]: http://www.python.org/dev/peps/pep-0008/
+[NumPy-assertions]: http://docs.scipy.org/doc/numpy/reference/routines.testing.html#asserts
 [basic-mean]: exercises/mean/basic/mean.py
 [exception-mean]: exercises/mean/exceptions/mean.py
 [embedded-test-mean]: exercises/embedded-tests/mean.py
 [test-mean]: exercises/test_mean.py
-[TDD]: http://en.wikipedia.org/wiki/Test-driven_development
 [fibonacci]: exercises/fibonacci