CherryPy - Testing
Testing is a process during which the application is conducted from different perspectives in order to −
- Find the list of issues
- Find differences between the expected and actual result, output, states, etc.
- Understand the implementation phase.
- Find the application useful for realistic purposes.
The goal of testing is not to put the developer at fault but to provide tools and improve the quality to estimate the health of the application at a given time.
Testing needs to be planned in advance. This calls for defining the purpose of testing, understanding the scope of test cases, making the list of business requirements and being aware of the risks involved in the different phases of the project.
Testing is defined as a range of aspects to be validated on a system or application. Following is a list of the common test approaches −
Unit testing − This is usually carried out by the developers themselves. This aims at checking whether a unit of code works as expected or not.
Usability testing − Developers may usually forget that they are writing an application for the end users who do not have knowledge of the system. Usability testing verifies the pros and cons of the product.
Functional/Acceptance testing − While usability testing checks whether an application or system is usable, functional testing ensures that every specified functionality is implemented.
Load and performance testing − This is carried out to understand whether the system can adjust to the load and performance tests to be conducted. This can lead to changes in hardware, optimizing SQL queries, etc.
Regression testing − It verifies that successive releases of a product do not break any of the previous functionalities.
Reliability and resilience testing − Reliability testing helps in validating the system application with the breakdown of one or several components.
Photoblog applications constantly use unit tests to check the following −
- New functionalities work correctly and as expected.
- Existing functionalities are not broken by new code release.
- Defects are fixed and remain fixed.
Python comes in with a standard unittest module offering a different approach to unit testing.
unittest is rooted in JUnit, a Java unit test package developed by Kent Beck and Erich Gamma. Unit tests simply return defined data. Mock objects can be defined. These objects allows testing against an interface of our design without having to rely on the overall application. They also provide a way to run tests in isolation mode with other tests included.
Let’s define a dummy class in the following way −
import unittest class DummyTest(unittest.TestCase): def test_01_forward(self): dummy = Dummy(right_boundary=3) self.assertEqual(dummy.forward(), 1) self.assertEqual(dummy.forward(), 2) self.assertEqual(dummy.forward(), 3) self.assertRaises(ValueError, dummy.forward) def test_02_backward(self): dummy = Dummy(left_boundary=-3, allow_negative=True) self.assertEqual(dummy.backward(), -1) self.assertEqual(dummy.backward(), -2) self.assertEqual(dummy.backward(), -3) self.assertRaises(ValueError, dummy.backward) def test_03_boundaries(self): dummy = Dummy(right_boundary=3, left_boundary=-3,allow_negative=True) self.assertEqual(dummy.backward(), -1) self.assertEqual(dummy.backward(), -2) self.assertEqual(dummy.forward(), -1) self.assertEqual(dummy.backward(), -2) self.assertEqual(dummy.backward(), -3)
The explanation for the code is as follows −
unittest module should be imported to provide unit test capabilities for the given class.
A class should be created by subclassing unittest.
Every method in the above code starts with a word test. All these methods are called by unittest handler.
The assert/fail methods are called by the test case to manage the exceptions.
Consider this as an example for running a test case −
if __name__ == '__main__': unittest.main()
The result (output) for running the test case will be as follows −
---------------------------------------------------------------------- Ran 3 tests in 0.000s OK
Once the application functionalities start taking shape as per the requirements, a set of functional testing can validate the application's correctness regarding the specification. However, the test should be automated for better performance which would require the use of third-party products such as Selenium.
CherryPy provides helper class like built-in functions to ease the writing of functional tests.
Depending on the application you are writing and your expectations in terms of volume, you may need to run load and performance testing in order to detect potential bottlenecks in the application that are preventing it from reaching a certain level of performance.
This section will not detail how to conduct a performance or load test as it is out of its the FunkLoad package.
The very basic example of FunkLoad is as follows −
from funkload.FunkLoadTestCase import FunkLoadTestCase class LoadHomePage(FunkLoadTestCase): def test_homepage(self): server_url = self.conf_get('main', 'url') nb_time = self.conf_getInt('test_homepage', 'nb_time') home_page = "%s/" % server_url for i in range(nb_time): self.logd('Try %i' % i) self.get(home_page, description='Get gome page') if __name__ in ('main', '__main__'): import unittest unittest.main()
Here is a detailed explanation of the above code −
The test case must inherit from the FunkLoadTestCase class so that the FunkLoad can do its internal job of tracking what happens during the test.
The class name is important as FunkLoad will look for a file based on the class name.
The test cases designed have direct access to the configuration files. Get() and post() methods are simply called against the server to get the response.