SpecialistOff.NET / Вопросы / Статьи / Фрагменты кода / Резюме / Метки / Помощь / Файлы

Назад

Writing Tests


Метки: python

Writing tests becomes very simple. Here’s an example that creates the necessary static inner class and performs trivial tests:

# UnitTesting/TestDemo.py
# Creating a test

class TestDemo:
    objCounter = 0
    id = ++objCounter
    def TestDemo(String s):
        print(s + ": count = " + id)

    def close(self):
        print("Cleaning up: " + id)

    def someCondition(self): return True
    class Test(UnitTest):
        TestDemo test1 = TestDemo("test1")
        TestDemo test2 = TestDemo("test2")
        def cleanup(self):
            test2.close()
            test1.close()

        def testA(self):
            print("TestDemo.testA")
            affirm(test1.someCondition())

        def testB(self):
            print("TestDemo.testB")
            affirm(test2.someCondition())
            affirm(TestDemo.objCounter != 0)

        # Causes the build to halt:
        #! def test3(): affirm(0)

The test3( ) method is commented out because, as you’ll see, it causes the automatic build of this book’s source-code tree to stop.

You can name your inner class anything you’d like; the only important factor is that it extends UnitTest. You can also include any necessary support code in other methods. Only public methods that take no arguments and return void will be treated as tests (the names of these methods are also not constrained).

The above test class creates two instances of TestDemo. The TestDemo constructor prints something, so that we can see it being called. You could also define a default constructor (the only kind that is used by the test framework), although none is necessary here. The TestDemo class has a close( )method which suggests it is used as part of object cleanup, so this is called in the overridden cleanup( ) method in Test.

The testing methods use the affirm( ) method to validate expressions, and if there is a failure the information is stored and printed after all the tests are run. Of course, the affirm( ) arguments are usually more complicated than this; you’ll see more examples throughout the rest of this book.

Notice that in testB( ), the private field objCounter is accessible to the testing code-this is because Test has the permissions of an inner class.

You can see that writing test code requires very little extra effort, and no knowledge other than that used for writing ordinary classes.

To run the tests, you use RunUnitTests.py (which will be introduced shortly). The command for the above code looks like this:

java com.bruceeckel.test.RunUnitTests TestDemo

It produces the following output:

test1: count = 1
test2: count = 2
TestDemo.testA
Cleaning up: 2
Cleaning up: 1
test1: count = 3
test2: count = 4
TestDemo.testB
Cleaning up: 4
Cleaning up: 3

All the output is noise as far as the success or failure of the unit testing is concerned. Only if one or more of the unit tests fail does the program returns a non-zero value to terminate the make process after the error messages are produced. Thus, you can choose to produce output or not, as it suits your needs, and the test class becomes a good place to put any printing code you might need- if you do this, you tend to keep such code around rather than putting it in and stripping it out as is typically done with tracing code.

If you need to add a test to a class derived from one that already has a test class, it’s no problem, as you can see here:

# UnitTesting/TestDemo2.py
# Inheriting from a class that
# already has a test is no problem.

class TestDemo2(TestDemo):
    def __init__(self, s): TestDemo.__init__(s)
    # You can even use the same name
    # as the test class in the base class:
    class Test(UnitTest):
        def testA(self):
            print("TestDemo2.testA")
            affirm(1 + 1 == 2)

        def testB(self):
            print("TestDemo2.testB")
            affirm(2 * 2 == 4)

Even the name of the inner class can be the same. In the above code, all the assertions are always true so the tests will never fail.