views:

284

answers:

2

I am just learning how to do unit-testing. I'm on Python / nose / Wing IDE.

(The project that I'm writing tests for is a simulations framework, and among other things it lets you run simulations both synchronously and asynchronously, and the results of the simulation should be the same in both.)

The thing is, I want some of my tests to use simulation results that were created in other tests. For example, synchronous_test calculates a certain simulation in synchronous mode, but then I want to calculate it in asynchronous mode, and check that the results came out the same.

How do I structure this? Do I put them all in one test function, or make a separate asynchronous_test? Do I pass these objects from one test function to another?

Also, keep in mind that all these tests will run through a test generator, so I can do the tests for each of the simulation packages included with my program.

+3  A: 

In general, I'd recommend not making one test depend upon another. Do the synchronous_test, do the asynchronous_test, compare them each to the expected correct output, not to each other.

So something like:

class TestSimulate(TestCase):
    def setup(self):
        self.simpack = SimpackToTest()
        self.initial_state = pickle.load("initial.state")
        self.expected_state = pickle.load("known_good.state")

    def test_simulate(self):
        state = simulate(self.simpack, self.initial_state)
        # assert_equal will require State to implement __eq__ in a meaningful
        # way.  If it doesn't, you'll want to define your own comparison 
        # function.
        self.assert_equal(self.expected_state, state)

    def test_other_simulate(self):
        foo = OtherThing(self.simpack)
        blah = foo.simulate(self.initial_state)
        state = blah.state
        self.assert_equal(self.expected_state, state)
keturn
So *where* do I calculate the expected correct output? Because the calculation of this output is something that needs to get tested by itself.
cool-RR
And how do you test *that*? Compare it to ... itself? You've got to have known good output somewhere. Load it from a pickle? (answer updated with code)
keturn
I guess you have a point. Though I won't load from a pickle-- Not easy enough to make changes that way. I think I'll consider doing it like in Gregg Lind's example.A question: Do you think it's bad if I just put many tests in one continuous function? Then I won't have to worry about these things, and if one thing fails I'll need to fix it anyway.
cool-RR
Smaller functions, in tests or in other code, usually make it easier to keep track of what's going on. And as you get more tests, you'll appreciate the ability of the testing tool to tell you exactly which tests failed and what kept working when you change something.
keturn
in addition, having the `setup` structure to provide a consistent states and simpacks for your different tests seems beneficial here.
keturn
My solution and this solution are very similar, which suggests we're both on the same meme. If you need to check an actual answer, then you need to have that answer somewhere, either in the code, in a json file (or pickle), or calculable using a known-good (maybe naive and slow) algorithm. You have to make a stand somewhere.
Gregg Lind
+2  A: 

You can add tests that need to calculate once per class to the "setup" of that class. As an example:

from nose.tools import *
class Test_mysim():
    def setup(self):
        self.ans = calculate_it_once()

    def test_sync(self):
        ans=calculate_it_sync()
        assert_equal(ans,self.ans)

    def test_async(self):
        ans=calculate_it_async()
        assert_equal(ans,self.ans)
Gregg Lind
And what happens when `calculate_it_once()` fails?
cool-RR
I assumed you knew the 'answer' (maybe by using random.setseed() or whatever). If not, then the best you can do is assert that sync and async are the same, and *that* is the test. I forked your code, but I haven't gotten a chance to look at it.
Gregg Lind