Snakes and Elephants Playing Nice Together: PHPUnit and py.test with Hudson post
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: ~~~ 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:
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:
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'."]