Unit Testing

One of the most interesting modules in Galah Interact is the interact.unittest module. It allows you to “load” any number of C++ files such that all of the native C++ classes and functions become available as Python classes and functions. This is done by leveraging the absolutely fantastic SWIG library which can automatically create bindings from C++ to a plethora of other languages. Please give the SWIG project as much support as you can as it is really a wonderful product.

In order to use the interact.unittest module, you need to make sure that you have SWIG installed, and that you have Python development headers installed, both of which are probably available through your distribution’s package manager (apt-get or yum for example).

Basic Unit Testing

Once you have it installed, you can start poking around with the following code.

main.cpp

#include <iostream>

using namespace std;

class Foo {
	int a_;
public:
	Foo(int a) : a_(a) {
		// Do nothing
	}

	Foo() : a_(0) {
		// Do nothing
	}

	int get_a() const {
		return a_;
	}
};

int bar(int a, int b) {
	cout << "a: " << a << " b: " << b << endl;
	return a + b;
}

int main() {
	return 0;
}

harness.py

import interact

student_code = interact.unittest.load_files(["main.cpp"])

print "---Running bar(3, 4)---"
return_value = student_code["main"]["bar"](3, 4)
print return_value

print "---Creating new Foo objects---"
Foo = student_code["main"]["Foo"]
new_foo = Foo(3)
new_foo_default = Foo()

print "---Printing get_a() on each foo instance---"
print new_foo.get_a()
print new_foo_default.get_a()

print "---Printing a_ value directly on each foo instance---"
print new_foo.a_
print new_foo_default.a_

Running the above Python script gives the following output:

---Running bar(3, 4)---
a: 3 b: 4
7
---Creating new Foo objects---
---Printing get_a() on each foo instance---
3
0
---Printing a_ value directly on each foo instance---
3
0

It should be clear that this makes it fairly easy to unit test some student’s code. You may notice that the bar function above prints out to standard output. This is a little problematic if you want to test what that function outputs, and it’s actually even more problematic in that if your harness prints things out to standard output when in Galah, the test server will get angry because you’ll make it so that the output is no longer proper JSON. To solve this, there is another handy library called interact.capture.

Using the interact.capture module

The interact.capture module exposes a function capture_function that forks a process before running a given function, and captures anything written to stdout or stderr (and even lets you control stdin). All while also allowing you to get the return value of the function and seeing any exceptions that are raised.

Using this function, we can test the bar function trivially.

import interact
from interact.capture import capture_function

student_code = interact.unittest.load_files(["main.cpp"])

captured_function = capture_function(student_code["main"]["bar"], 3, 4)

# Wait for the function to end.
captured_function.wait()

print "The function returned:", repr(captured_function.return_value)
print "The function wrote to stdout:", repr(captured_function.stdout.read())
print "The function wrote to stderr:", repr(captured_function.stderr.read())

Note that capture_function returns a special CapturedFunction object. You should briefly glance over its documentation to get an understanding of what it does and why it exists.

Running the above Python scripts outputs:

The function returned: 7
The function wrote to stdout: 'a: 3 b: 4\n'
The function wrote to stderr: ''

Go ahead and try to play around with interact.unittest and interact.capture. There is a lot of very cool things you can do with them!