Chapter 6. Integrating Automated Tests with Continuous Integration

In this chapter, we will cover:

  • Generating a continuous integration report for Jenkins with NoseXUnit
  • Configuring Jenkins to run Python tests upon commit
  • Configuring Jenkins to run Python tests when scheduled
  • Generating a continuous integration report for TeamCity using teamcity-nose
  • Configuring TeamCity to run Python tests upon commit
  • Configuring TeamCity to run Python tests when scheduled

Introduction

The classic software development process known as the waterfall model involves the following stages:

  1. Requirements are collected and defined.
  2. Designs are drafted to satisfy the requirements.
  3. An implementation strategy is written to meet the design.
  4. Coding is done.
  5. The coded implementation is tested.
  6. The system is integrated with other systems as well as future versions of this system.

In the waterfall model, these steps are often spread across several months of work. What this means is that the final step of integration with external systems is done after several months and often takes a lot of effort.

Continuous integration (CI) remedies the deficiencies of the waterfall model by introducing the concept of writing tests that exercise these points of integration and having them run automatically whenever the code is checked into the system. Teams that adopt continuous integration often adopt a corresponding policy of immediately fixing the baseline if the test suite fails.

This forces the team to continuously keep their code working and integrated, thus making this final step relatively cost free.

Teams that adopt a more agile approach work in much shorter cycles. Teams may work anywhere from weekly to monthly coding sprints. Again, by having integrating test suites run with every check in, the baseline is always kept functional; thus, ready for delivery at any time.

This prevents the system from being in a non-working state that is only brought into the working state at the end of a sprint or at the end of a waterfall cycle. It opens the door to more code demonstrations with either the customer or management, in which feedback can be garnered and more proactively fed into development.

This chapter is more focused on integrating automated tests with CI systems rather than writing the tests. For that reason, we will re-use the following Shopping Cart application. Create a new file called cart.py and enter the following code into it:

class ShoppingCart(object):
    def __init__(self):
        self.items = []

    def add(self, item, price):
        for cart_item in self.items:
            # Since we found the item, we increment
            # instead of append
            if cart_item.item == item:
                cart_item.q += 1
                return self

        # If we didn't find, then we append
        self.items.append(Item(item, price))
        return self

    def item(self, index):
        return self.items[index-1].item

    def price(self, index):
        return self.items[index-1].price * self.items[index-1].q

    def total(self, sales_tax):
        sum_price = sum([item.price*item.q for item in self.items])
        return sum_price*(1.0 + sales_tax/100.0)

    def __len__(self):
        return sum([item.q for item in self.items])

class Item(object):
    def __init__(self, item, price, q=1):
        self.item = item
        self.price = price
        self.q = q

To exercise this simple application, the following set of unit tests will be used by various recipes in this chapter to demonstrate continuous integration. Create another file called tests.py and enter the following test code into it:

from cart import *
import unittest

class ShoppingCartTest(unittest.TestCase):
    def setUp(self):
        self.cart = ShoppingCart().add("tuna sandwich", 15.00)

    def test_length(self):
        self.assertEquals(1, len(self.cart))

    def test_item(self):
        self.assertEquals("tuna sandwich", self.cart.item(1))

    def test_price(self):
        self.assertEquals(15.00, self.cart.price(1))

    def test_total_with_sales_tax(self):
        self.assertAlmostEquals(16.39, 
                                self.cart.total(9.25), 2)

This simple set of tests doesn't look very impressive, does it? In fact, it isn't really integration testing like we were talking about earlier, but instead it appears to be some basic unit tests, right?

Absolutely! This chapter isn't focusing on writing test code. So, if this book is about code recipes, why are we focusing on tools? Because there is more to making automated testing work with your team than writing tests. It's important to become aware of tools that take the concepts of automating tests and leveraging them into our development cycles.

Continuous integration products are a valuable tool, and we need to see how to link them with our test code, in turn allowing the whole team to come on board and make testing a first class citizen of our development process.

This chapter explores two powerful CI products: Jenkins and TeamCity.

Jenkins (http://jenkins-ci.org/) is an open source product that was led by a developer originally from SUN Microsystems, who left after its acquisition by Oracle. It has a strong developer community with many people providing patches, plugins, and improvements. It was originally called Hudson, but the development community voted to rename it to avoid legal entanglements. There is more history to the entire Hudson/Jenkins naming that can be read online, but it's not relevant to the recipes in this book.

TeamCity (http://www.jetbrains.com/teamcity/) is a product created by Jet Brains, the same company that produces commercial products such as IntelliJ IDE, ReSharper, and PyCharm IDE. The Professional Edition is a free version that will be used in this chapter to show another CI system. It has an enterprise, commercial upgrade, which you can evaluate for yourself.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.190.217.253