Unit Testing Using Py Unit Monther Suboh 200820311
Unit Testing Using Py. Unit Monther Suboh 200820311 Yazan Hamam 200810019 Saddam Al-Mahasneh 200810845 Miran Ahmad 200810194
Overview • Unit Testing Basics: What, Why, When • How: Python Unit Test Class • Unit Test Writing Tips and Resources
Unit Testing Basics • Functional tests: done by QA to test functionality according to a test plan based on requirements and design specs. • Unit tests: done by developers to test specific code. Typically “white box” testing. • Essential part of Extreme Programming and other agile methods.
Why Write Unit Tests • Increase developers’ confidence in code. If someone challenges your work, you can say “the tests passed. ” • Avoid regression. If unit test suite is run frequently, you know when new code breaks old code. • If you write tests first, you know when you’re done, i. e. , when the tests pass. • Encourages minimal interfaces and modularity.
When to Write/Run Unit Tests • Always! • Before you check code into repository, so you know your code works. • Before debugging, to ease the process and help you know when you’re done.
Test Writing Tips • Make code modular: use interfaces/template classes/abstract base classes. • Use mock objects to inspect behavior of object you’re testing and to stand in for “heavy” objects, e. g. , you don’t want to do network I/O in a unit test. • Modular, loosely coupled interfaces make mock objects possible. • Excessive coupling is enemy of unit testing.
Using Py. Unit to write your own tests • Installation The classes needed to write tests are to be found in the 'unittest' module. This module is part of the standard Python library for Python 2. 1 and later. If you are using an older Python version, you should obtain the module from the separate Py. Unit distribution.
An introduction to Test. Cases • The basic building blocks of unit testing are 'test cases' -- single scenarios that must be set up and checked for correctness. In Py. Unit, test cases are represented by the Test. Case class in the unittest module. To make your own test cases you must write subclasses of Test. Case. • An instance of a Test. Case class is an object that can completely run a single test method, together with optional set-up and tidy-up code.
Creating a simple test case • The simplest test case subclass will simply override the run. Test method in order to perform specific testing code: import unittest class Default. Widget. Size. Test. Case(unittest. Test. Case): def run. Test(self): widget = Widget("The widget") assert widget. size() == (50, 50), 'incorrect default size'
Note that in order to test something, we just use the built-in 'assert' statement of Python. If the assertion fails when the test case runs, an Assertion. Error will be raised, and the testing framework will identify the test case as a 'failure'. Other exceptions that do not arise from explicit 'assert' checks are identified by the testing framework as 'errors'.
Re-using set-up code: creating 'fixtures' • Now, such test cases can be numerous, and their set-up can be repetitive. In the above case, constructing a 'Widget' in each of 100 Widget test case subclasses would mean unsightly duplication. • Luckily, we can factor out such set-up code by implementing a hook method called set. Up, which the testing framework will automatically call for us when we run the test:
import unittest class Simple. Widget. Test. Case(unittest. Test. Case): def set. Up(self): self. widget = Widget("The widget") class Default. Widget. Size. Test. Case(Simple. Widget. Test. Case): def run. Test(self): assert self. widget. size() == (50, 50), 'incorrect default size' class Widget. Resize. Test. Case(Simple. Widget. Test. Case): def run. Test(self): self. widget. resize(100, 150) assert self. widget. size() == (100, 150), 'wrong size after resize'
• If the set. Up method raises an exception while the test is running, the framework will consider the test to have suffered an error, and the run. Test method will not be executed. • Similarly, we can provide a tear. Down method that tidies up after the run. Test method has been run: import unittest class Simple. Widget. Test. Case(unittest. Test. Case): def set. Up(self): self. widget = Widget("The widget") def tear. Down(self): self. widget. dispose() self. widget = None • If set. Up succeeded, the tear. Down method will be run regardless of whether or not run. Test succeeded. • Such a working environment for the testing code is termed a fixture.
Test. Case classes with several test methods Often, many small test cases will use the same fixture. In this case, we would end up subclassing Simple. Widget. Test. Case into many small one-method classes such as Default. Widget. Size. Test. Case. This is time-consuming and discouraging import unittest class Widget. Test. Case(unittest. Test. Case): def set. Up(self): self. widget = Widget("The widget") def tear. Down(self): self. widget. dispose() self. widget = None def test. Default. Size(self): assert self. widget. size() == (50, 50), 'incorrect default size' def test. Resize(self): self. widget. resize(100, 150) assert self. widget. size() == (100, 150), 'wrong size after resize' •
Test. Case classes with several test methods • Here we have not provided a run. Test method, but have instead provided two different test methods. Class instances will now each run one of the test methods, with self. widget created and destroyed separately for each instance. When creating an instance we must specify the test method it is to run. We do this by passing the method name in the constructor: default. Size. Test. Case = Widget. Test. Case("test. Default. Size") resize. Test. Case = Widget. Test. Case("test. Resize")
Running tests • The unittest module contains a function called main, which can be used to easily turn a test module into a script that will run the tests it contains. The main function uses the unittest. Test. Loader class to automatically find and load test cases within the current module. • Therefore, if you name your test methods using the test* convention, you can place the following code at the bottom of your test module: if __name__ == "__main__": unittest. main()
Resources • http: //pyunit. sourceforge. net/pyunit. html • http: //www. junit. org/
- Slides: 17