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.
#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;
}
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!