Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds
Arrow up icon
GO TO TOP
Test Driven Python Development

You're reading from   Test Driven Python Development Develop high-quality and maintainable Python applications using the principles of test-driven development

Arrow left icon
Product type Paperback
Published in Apr 2015
Publisher Packt
ISBN-13 9781783987924
Length 264 pages
Edition 1st Edition
Languages
Tools
Arrow right icon
Author (1):
Arrow left icon
Siddharta Govindaraj Siddharta Govindaraj
Author Profile Icon Siddharta Govindaraj
Siddharta Govindaraj
Arrow right icon
View More author details
Toc

Table of Contents (14) Chapters Close

Preface 1. Getting Started with Test-Driven Development FREE CHAPTER 2. Red-Green-Refactor – The TDD Cycle 3. Code Smells and Refactoring 4. Using Mock Objects to Test Interactions 5. Working with Legacy Code 6. Maintaining Your Test Suite 7. Executable Documentation with doctest 8. Extending unittest with nose2 9. Unit Testing Patterns 10. Tools to Improve Test-Driven Development A. Answers to Exercises B. Working with Older Python Versions Index

Reorganizing the test code

We've added the test cases in the same file as the code. This is a good, simple way to add test cases to standalone scripts and applications that are not too complex. However, for larger applications, it is a good idea to keep test code separate from production code.

There are two common patterns for organizing test code this way.

The first pattern is to keep test code in a separate root directory, as shown in the following:

root
|
+- package
|  |
|  +- file1
|  +- file2
|
+- test
   |
   +- test_file1
   +- test_file2

The other pattern is to keep test code as a submodule of the main code, as shown in the following:

root
|
+- package
   |
   +- file1
   +- file2
   +- test
      |
      +- test_file1
      +- test_file2

The first pattern is commonly used for standalone modules as it allows us to distribute the code and tests together. Tests can generally be run without having to perform a lot of setup or configuration. The second pattern has an advantage when the application has to be packaged without the test code, for example when deploying to production servers, or distributing to customers (in the case of a commercial application). However, both the patterns are in popular use, and it is mainly a personal preference as to which method to use.

We are going to follow the first pattern in this book. To get started, create a directory called tests inside the stock_alerter directory. Next, create a file called test_stock.py in this directory. We will put all our test cases in one-to-one correspondence with the source file. This means, a file called sample.py will have its test cases in the tests/test_sample.py file. This is a simple naming convention that helps to quickly locate test cases.

Finally, we move our test cases into this file. We also need to import the Stock class to be able to use it in the test case. Our test_stock.py file now looks like the following:

import unittest
from ..stock import Stock

class StockTest(unittest.TestCase):
    def test_price_of_a_new_stock_class_should_be_None(self):
        stock = Stock("GOOG")
        self.assertIsNone(stock.price)

Remember to remove the import unittest line from stock.py, now that it no longer contains the test code. Previously we had just one standalone script, but we now have a stock_alerter module and a stock_alerter.tests submodule. Since we are now working with modules, we should also add in an empty __init__.py file in both the stock_alerter and tests directories.

Our file layout should now be like the following:

src
|
+- stock_alerter
   |
   +- __init__.py
   +- stock.py
   +- tests
      +- __init__.py
      +- test_stock.py

Running the tests after the reorganization

If you have noticed, we no longer have a call to unittest.main() in the test code. Including a call to unittest.main() works well with individual scripts since it allows us to run the tests by simply executing the file. However, it is not a very scalable solution. If we have hundreds of files, we would like to run all the tests at once, and not have to execute each file individually.

To address this, Python 3 comes with a very nice test discovery and execution capability from the command line. Simply go into the src directory and run the following command:

  • Windows:
    python.exe -m unittest
    
  • Linux/Mac:
    python3 -m unittest
    

This command will go through the current directory and all subdirectories and run all the tests that are found. This is the default autodiscover mode of execution, where the command searches all the files and runs the tests. Autodiscovery can also be explicitly run with the following command:

python3 -m unittest discover

Autodiscover can be customized to check in specific directories or files with the following parameters:

  • -s start_directory: Specify the start directory from where the discovery should start. This defaults to the current directory.
  • -t top_directory: Specify the top-level directory. This is the directory from which imports are performed. This is important if the start directory is inside the package and you get errors due to incorrect imports. This defaults to the start directory.
  • -p file_pattern: The file pattern that identifies test files. By default it checks for python files that start with test. If we name our test files something else (for example, stock_test.py), then we have to pass in this parameter so that the file is correctly identified as a test file.

To illustrate the difference between the start and top directory, run the following command from the src directory:

python3 -m unittest discover -s stock_alerter

The preceding command will fail with an import error. The reason is because when the start directory is set to stock_alerter, then the tests directory is imported as a top-level module, and the relative import fails. To get around this, we need to use the following command:

python3 -m unittest discover -s stock_alerter -t .

This command will import all modules relative to the top directory, and so stock_alerter correctly becomes the main module.

You can also disable autodiscovery and specify only certain tests to be run:

  • Passing in a module name will only run the tests within that module. For example, python3 -m unittest stock_alerter.tests.test_stock will run the tests only in test_stock.py.
  • You can further refine to a specific class or method, such as python3 -m unittest stock_alerter.tests.test_stock.StockTest.
You have been reading a chapter from
Test Driven Python Development
Published in: Apr 2015
Publisher: Packt
ISBN-13: 9781783987924
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €18.99/month. Cancel anytime