Uncategorized

Eutester Basics Part III: Creating your first testcase

Intro to unittest

When writing test cases using Eutester one can simply write a single Python script that runs through from start to finish and exits when it encounters an error. This kind of script will be easy to put together but will not be very maintainable moving forward when you want to reuse routines in a different script or share your work with the community. In order to make sharing of test case code more efficient we have chosen to leverage the unittest library present in the standard library since Python 2.6. This library for creating, cataloging, and executing testcases adds value in creating cases by providing some constructs that will be familiar to anyone who has worked or contributed as a tester. In this tutorial I will show how to leverage unittest to write a test case that can be contributed back to the community or used as reproducible steps for a bug filed against Eucalyptus.

Unittest Basics

A test case can be thought of as a series of steps executed in a particular order that identify whether a system is operating properly. Each of these steps have an expected result. When the expected results are not met the case can be marked as a failure. Python unittest allows us to quickly create these test cases and reuse code from case to case by allowing us to inherit from the TestCase class.

import unittest
from eucaops import Eucaops

class MyFirstTest(unittest.TestCase):

    def setUp(self):
        self.tester = Eucaops(credpath="/home/ubuntu/.euca")
        self.keypair = self.tester.add_keypair()
        self.group = self.tester.add_group()
        self.tester.authorize_group(self.group)
        self.tester.authorize_group(self.group, port=-1, protocol="icmp")
        self.reservation = None

    def testInstance(self):
        #### INTERESTING STUFF GOES HERE
        pass        

    def tearDown(self):
        if self.reservation is not None:
            self.tester.terminate_instances(self.reservation)
        self.tester.delete_keypair(self.keypair)
        self.tester.local("rm " + self.keypair.name + ".pem")
        self.tester.delete_group(self.group)

As you can see from above, two of the major building blocks of a test case are the setup and teardown phases. The setup phase is giving the test case the necessary artifacts to execute. Our first case requires a keypair and a security group authorized for both SSH and Ping. The teardown phase will then remove the artifacts created regardless of whether the test passed or failed. Cleanup up after your tests will be very important as you begin to run many cases and suites against your system. Each test case should be able to run without leaving behind artifacts and without relying on artifacts that it did not create. Making tests idempotent will make it easier for developers, testers, and others to reproduce the exact condition you produced with your case.

Now that we have prepared our test case with both setup and teardown steps it is time to create a routine that actually tests something. Our test method will validate the following:

  1. Running an instance
  2. Network connectivity between the instance and the test machine
  3. Commands can be executed on the remote host

We will be filling out the testInstance method with the following:

def testInstance(self):
        image = self.tester.get_emi(root_device_type="instance-store")
        ### 1) Run an instance
        try:
            self.reservation = self.tester.run_instance(image, self.keypair.name, self.group.name)
        except Exception, e:
            self.fail("Caught an exception when running the instance: " + str(e))
        for instance in self.reservation.instances:
            ### 2) Ping the instance
            ping_result = self.tester.ping(instance.public_dns_name)
            self.assertTrue(ping_result, "Ping to instance failed")
            ### 3) Run command on instance
            uname_result = instance.sys("uname -r")
            self.assertNotEqual(len(uname_result), 0, "uname failed")

Upon inspection of this code you will notice that we are using  the assertion methods, another great element provided to us by the unittest framework. These methods are useful for making sure that your script does not continue to execute after a failure has been encountered. In our case we are using assertTrue to make sure the ping succeeded before proceeding. The next assertion we use is assertNotEqual when checking that the result of running the uname command actually has some output.

Running your test

Once we have setUp, tearDown, and one other test method, we are ready to run this testcase. In order to run the case we need to add a main function that will be called when we run this class from the command line. In order to do this add the following to the bottom of your testcase file:

if __name__ == '__main__':
    unittest.main()

After setting execution permissions, you will be able to call your testcase script directly from the command line. The trick here is that we prefaced our method name with the word “test” so the unittest library knows that it is a special method and requires that we run the setUp and tearDown methods first.  You can build out as many test methods as you’d like in this one file using the same setUp and tearDown methods.

Standard

6 thoughts on “Eutester Basics Part III: Creating your first testcase

  1. Pingback: Writing a test case « The Mind of Mattamizer

  2. Deependra Shekhawat says:

    Hi Vic, I have a confusion on that last section about calling unittest.main() is it part of the class or is it separate? If its separate I was not able to use this in my test case. Can you provide some pointers?🙂

  3. Pingback: 4/30 « michaelkenny2

  4. Pingback: 4/23 « michaelkenny2

  5. Pawan says:

    Hai I am working in a Research Organizaiton. And i am new to Eutester. So I need Documentation How to Program Test Cases Cloud Setup{Eucalyptus cloud stack}. Please share Documents It will be Very Helpful .

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s