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.

unittestThe 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 withtestAt 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 thats.costProperty returns the correct value (49010.0).
  • Make sure thats.sell()The method works normally. It should decrease accordinglys.shares.
  • Make sure thats.sharesProperty 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…