Many edits

This commit is contained in:
David Beazley
2020-05-28 17:41:59 -05:00
parent 9572f707b2
commit a83a9cf064
23 changed files with 467 additions and 210 deletions

View File

@@ -1,14 +1,18 @@
[Contents](../Contents) \| [Previous (7.5 Decorated Methods)](../07_Advanced_Topics/05_Decorated_methods) \| [Next (8.2 Logging)](02_Logging)
# 8.1 Testing
## Testing Rocks, Debugging Sucks
The dynamic nature of Python makes testing critically important to most applications.
There is no compiler to find your bugs. The only way to find bugs is to run the code and make sure you try out all of its features.
The dynamic nature of Python makes testing critically important to
most applications. There is no compiler to find your bugs. The only
way to find bugs is to run the code and make sure you try out all of
its features.
## Assertions
The assertion statement is an internal check for the program.
If an expression is not true, it raises a `AssertionError` exception.
The `assert` statement is an internal check for the program. If an
expression is not true, it raises a `AssertionError` exception.
`assert` statement syntax.
@@ -22,15 +26,18 @@ For example.
assert isinstance(10, int), 'Expected int'
```
It shouldn't be used to check the user-input.
It shouldn't be used to check the user-input (i.e., data entered
on a web form or something). It's purpose is more for internal
checks and invariants (conditions that should always be true).
### Contract Programming
Also known as Design By Contract, liberal use of assertions is an approach for designing
software. It prescribes that software designers should define precise
interface specifications for the components of the software.
Also known as Design By Contract, liberal use of assertions is an
approach for designing software. It prescribes that software designers
should define precise interface specifications for the components of
the software.
For example, you might put assertions on all inputs and outputs.
For example, you might put assertions on all inputs of a function.
```python
def add(x, y):
@@ -39,7 +46,8 @@ def add(x, y):
return x + y
```
Checking inputs will immediately catch callers who aren't using appropriate arguments.
Checking inputs will immediately catch callers who aren't using
appropriate arguments.
```python
>>> add(2, 3)
@@ -64,9 +72,12 @@ assert add(2,2) == 4
This way you are including the test in the same module as your code.
*Benefit: If the code is obviously broken, attempts to import the module will crash.*
*Benefit: If the code is obviously broken, attempts to import the
module will crash.*
This is not recommended for exhaustive testing.
This is not recommended for exhaustive testing. It's more of a
basic "smoke test". Does the function work on any example at all?
If not, then something is definitely broken.
### `unittest` Module
@@ -79,10 +90,10 @@ def add(x, y):
return x + y
```
You can create a separate testing file. For example:
Now, suppose you want to test it. Create a separate testing file like this.
```python
# testsimple.py
# test_simple.py
import simple
import unittest
@@ -91,7 +102,7 @@ import unittest
Then define a testing class.
```python
# testsimple.py
# test_simple.py
import simple
import unittest
@@ -106,7 +117,7 @@ The testing class must inherit from `unittest.TestCase`.
In the testing class, you define the testing methods.
```python
# testsimple.py
# test_simple.py
import simple
import unittest
@@ -146,14 +157,15 @@ self.assertAlmostEqual(x,y,places)
self.assertRaises(exc, callable, arg1, arg2, ...)
```
This is not an exhaustive list. There are other assertions in the module.
This is not an exhaustive list. There are other assertions in the
module.
### Running `unittest`
To run the tests, turn the code into a script.
```python
# testsimple.py
# test_simple.py
...
@@ -164,7 +176,7 @@ if __name__ == '__main__':
Then run Python on the test file.
```bash
bash % python3 testsimple.py
bash % python3 test_simple.py
F.
========================================================
FAIL: test_simple (__main__.TestAdd)
@@ -180,7 +192,8 @@ FAILED (failures=1)
### Commentary
Effective unit testing is an art and it can grow to be quite complicated for large applications.
Effective unit testing is an art and it can grow to be quite
complicated for large applications.
The `unittest` module has a huge number of options related to test
runners, collection of results and other aspects of testing. Consult
@@ -188,23 +201,39 @@ the documentation for details.
### Third Party Test Tools
We won't cover any third party test tools in this course.
The built-in `unittest` module has the advantage of being available everywhere--it's
part of Python. However, many programmers also find it to be quite verbose.
A popular alternative is [pytest](https://docs.pytest.org/en/latest/). With pytest,
your testing file simplifies to something like the following:
However, there are a few popular alternatives and complements to
`unittest`.
```python
# test_simple.py
import simple
* [pytest](https://pytest.org) - A popular alternative.
* [coverage](http://coverage.readthedocs.io) - Code coverage.
def test_simple():
assert simple.add(2,2) == 4
def test_str():
assert simple.add('hello','world') == 'helloworld'
```
To run the tests, you simply type a command such as `python -m pytest`. It will
discover all of the tests and run them.
There's a lot more to `pytest` than this example, but it's usually pretty easy to
get started should you decide to try it out.
## Exercises
In this exercise, you will explore the basic mechanics of using
Python's `unittest` module.
In earlier exercises, you wrote a file `stock.py` that contained a `Stock`
class. For this exercise, it assumed that you're using the code written
for Exercise 7.3. If, for some reason, that's not working,
you might want to copy the solution from `Solutions/7_3` to your working
In earlier exercises, you wrote a file `stock.py` that contained a
`Stock` class. For this exercise, it assumed that you're using the
code written for [Exercise
7.9](../07_Advanced_Topics/03_Returning_functions) involving
typed-properties. If, for some reason, that's not working, you might
want to copy the solution from `Solutions/7_9` to your working
directory.
### Exercise 8.1: Writing Unit Tests