Many edits
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user