@TheKeyboard

Snakes and Elephants Playing Nice Together: PHPUnit and py.test With Hudson

| Comments

These days, it’s becoming increasingly harder to find web applications that are homogenous in terms of the tools they use to Get Things Done. The ability to build the web front-end of your site using PHP but a critical part that requires asynchronous processing using Node.js is something that is both exciting and, well, practical. Loosely coupled components, passing messages to each other, is great architecture to try and build if you have both the skills and patience to make it work.

For a project at work, I am using PHP (specifically Zend Framework) for the front-end but are using Python scripts run as a cron-job (and also on-demand when statistical corrections occur) to collect raw stats for a variety of sports, and then generate fantasy point totals for the games we run. I’m already using PHPUnit for tests of the front end, and I decided to to use py.test to test my Python scripts.

Setting up tests in Python was pretty simple. Here’s one of my test scripts:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import py
import baseball_scoring

def test_batter_empty_data_set():
    expected_points = 0
    test_data = dict()
    test_points = baseball_scoring.batter_points(test_data)
    assert expected_points == test_points

def test_batter_simple():
    test_data = {
        'hits': 4,
        'doubles': 1,
        'triples': 1,
        'home_runs': 1,
        'runs_scored': 1,
        'rbi': 1,
        'stolen_bases': 1,
        'league': 'bluejays2010'
    }
    expected_points = 11
    test_points = baseball_scoring.batter_points(test_data)
    assert expected_points == test_points

def test_pitcher_empty_data_set():
    expected_points = 0
    test_data = dict()
    test_points = baseball_scoring.pitcher_points(test_data)
    assert expected_points == test_points

def test_pitcher_simple():
    test_data = {
        'wins': 1,
        'losses': 0,
        'saves': 0,
        'strikeouts': 7,
        'complete_games': 1,
        'shutouts': 1,
        'league': 'bluejays2010'
    }
    expected_points = 25
    test_points = baseball_scoring.pitcher_points(test_data)
    assert expected_points == test_points

Very similar to tests with PHPUnit, right? So now that I had both PHPUnit tests and py.tests tests (hrm, is there are better way to say that?) to run, I had to figure out how to automatically run them. More specifically, how to get our installation of Hudson to run them.

Getting PHPUnit to play nice with Hudson was relatively easy. I installed the NUnit plugin for Hudson, made sure I installed phpunit, and then I added it’s use to my build scripts. However, the strength of Hudson is that with the use of another plugin I could read reports of all those tests. So when things failed, I would not have to look at the console output to figure things out. There’s a place in the Hudson config where you can configure this: PHPUnit configuration in Hudson
Now, I figured that the same thing could be done with py.test. It had an option so that at run-time you could tell it where to put JUnit-compatible test result files. After a little tinkering, I got it to work. First step was adding execution of it to my build script. Here is the latest-and-greatest version of that script:

mkdir /var/www/games-hudson/${BUILD_ID}
cd ${WORKSPACE}/games
/usr/local/zend/bin/php doctrine-cli migrate
cd ${WORKSPACE}/games/tests
/usr/local/zend/bin/phpunit --log-junit=${WORKSPACE}/build/logs/phpunit-results.xml
cd ${WORKSPACE}/games/scripts
/usr/bin/py.test --junitxml=${WORKSPACE}/build/logs/pytest-xmlrunner.xml
cp -R /var/lib/hudson/jobs/${JOB_NAME}/workspace/games/* /var/www/games-hudson/${BUILD_ID}
chmod 777 /var/www/games-hudson/${BUILD_ID}/tmp
rm -rf /var/www/games-hudson/current
ln -sf /var/www/games-hudson/${BUILD_ID} /var/www/games-hudson/current

Next, I then told Huson where it could find the JUnit-compatible files generated by py.test:
Telling Hudson where to find the py.test output

So there you have it. Now, when I do a commit and trigger a Hudson build, both my PHPUnit and Python tests get run. And there is output to check, so I don’t have to dig through console output to figure things out. [topicblocks id=”/en/phpunit” comment=”When you publish this post, this WordPress shortcode will display the TopicBlock you created about ‘PHPUnit’.”]