Directory | in the previous section (7.5 | decoration method in the next section (8.2 log)
8.1 test
Testing Rocks, Debugging Sucks
The dynamic nature of Python makes testing essential for most programs. The compiler won’t find your bugs, and the only way to find bugs is to run the code and make sure you try all the features.
Assertions
The ASSERT statement is used for internal checks of the program. If the expression is not true, an AssertionError exception is raised.
Assert statement syntax:
assert <expression> [, 'Diagnostic message']
Copy the code
Example:
assert isinstance(10.int), 'Expected int'
Copy the code
The Assert statement should not be used to check user input (for example, data entered in a Web form). Assert statements are intended for internal checks or for invariants (invariant, the condition that is always True).
Programming by contract
Contract programming, also known as Design By Contract, is a method of software Design that uses assertions freely. Programming by contract specifies that software designers should define precise interface specifications for software components.
For example, you can use assertions in all function inputs:
def add(x, y) :
assert isinstance(x, int), 'Expected int'
assert isinstance(y, int), 'Expected int'
return x + y
Copy the code
If the function caller does not use the correct parameters, the check input can be captured immediately.
>>> add(2.3)
5
>>> add('2'.'3')
Traceback (most recent call last):
...
AssertionError: Expected int
>>>
Copy the code
The inline test
Assertions can also be used for simple testing.
def add(x, y) :
return x + y
assert add(2.2) = =4
Copy the code
This way, you can include tests and code in the same module.
Benefit: If the code is obviously broken, trying to import the module will cause the program to crash.
This is not recommended for exhaustive testing. It’s more like a basic “smoke test.” Does the function work on all use cases? If not, there is something wrong.
unittest
The module
Suppose you have the following code:
# simple.py
def add(x, y) :
return x + y
Copy the code
Now, if you want to test this code, create a separate test file like this:
# test_simple.py
import simple
import unittest
Copy the code
Then define a test class:
# test_simple.py
import simple
import unittest
# Notice that it inherits from unittest.TestCase
class TestAdd(unittest.TestCase) :.Copy the code
Test classes must inherit from UnitTest.testCase.
In the test class, define test methods:
# test_simple.py
import simple
import unittest
# Notice that it inherits from unittest.TestCase
class TestAdd(unittest.TestCase) :
def test_simple(self) :
# Test with simple integer arguments
r = simple.add(2.2)
self.assertEqual(r, 5)
def test_str(self) :
# Test with strings
r = simple.add('hello'.'world')
self.assertEqual(r, 'helloworld')
Copy the code
Important: The name of each method must start withtest
At the beginning.
useunittest
Unittest has several assertions built into it, each of which diagnoses a different thing.
# Assert that expr is True
self.assertTrue(expr)
# Assert that x == y
self.assertEqual(x,y)
# Assert that x ! = y
self.assertNotEqual(x,y)
# Assert that x is near y
self.assertAlmostEqual(x,y,places)
# Assert that callable(arg1,arg2,...) raises exc
self.assertRaises(exc, callable, arg1, arg2, ...)
Copy the code
The list above is not a complete list, and the UnitTest module has other assertions.
rununittest
To run the tests, convert the code to a script.
# test_simple.py.if __name__ == '__main__':
unittest.main()
Copy the code
Then execute the test file using Python:
bash % python3 test_simple.py
F.
========================================================
FAIL: test_simple (__main__.TestAdd)
--------------------------------------------------------
Traceback (most recent call last):
File "testsimple.py", line 8, intest_simple self.assertEqual(r, 5) AssertionError: 4 ! = 5 -------------------------------------------------------- Ran 2 testsin0.000 s FAILED (failures = 1)Copy the code
instructions
Effective unit testing is an art form. For large applications, unit testing can become very complex.
The UnitTest module has a number of options related to Test runners, collection of results, and other aspects of testing. Please refer to the documentation for more information.
Third Party testing tools
Although the built-in UnitTest module has the advantage that it can be used anywhere — because it is part of Python — many programmers also find UnitTest tedious. Another popular testing tool is PyTest. With PyTest, the test file can be simplified into the following form:
# test_simple.py
import simple
def test_simple() :
assert simple.add(2.2) = =4
def test_str() :
assert simple.add('hello'.'world') = ='helloworld'
Copy the code
To run the test, you simply type a command, such as python -m pytest. It will find all the tests and run them.
There’s a lot more to PyTest than this example. It’s usually easy to get started if you decide to give it a try.
practice
In this exercise, we will explore the basic mechanics of using the Python Unittest module.
In the previous exercise, we wrote a stock.py file containing the Stock class. For this exercise, assume that we use the typedProperty-related code written in Exercise 7.9. If for some reason the code in Exercise 7.9 does not work properly, you can copy typedProperty.py from Solutions/7_9 into the working directory.
Exercise 8.1: Writing unit tests
Create a separate test_stock.py file to write unit test sets for Stock. To get you started, here’s a little test instance creation code:
# test_stock.py
import unittest
import stock
class TestStock(unittest.TestCase) :
def test_create(self) :
s = stock.Stock('GOOG'.100.490.1)
self.assertEqual(s.name, 'GOOG')
self.assertEqual(s.shares, 100)
self.assertEqual(s.price, 490.1)
if __name__ == '__main__':
unittest.main()
Copy the code
Running the unit test, you should get some output like this:
. -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- Ran 1 tests in 0.000 s OKCopy the code
Then, write additional unit tests to check the following:
- Make sure that
s.cost
Property returns the correct value (49010.0). - Make sure that
s.sell()
The method works normally. It should decrease accordinglys.shares
. - Make sure that
s.shares
Property can only be set to an integer value.
For the last part, you need to check the exception trigger. An easy way to do this is to use the following code:
class TestStock(unittest.TestCase) :.def test_bad_shares(self) :
s = stock.Stock('GOOG'.100.490.1)
with self.assertRaises(TypeError):
s.shares = '100'
Copy the code
Directory | in the previous section (7.5 | decoration method in the next section (8.2 log)
Note: The full translation can be found at github.com/codists/pra…