views:

117

answers:

3

I would like to unit test a method on a class I have made, but this method requires another method to be called first. Example:

// This would work
MyClass myClass1 = new MyClass(mockDevice);
myClass1.Run(myDatastructure);
myClass1.Stop();

// This would throw an InvalidOperationException
MyClass myClass2 = new MyClass(mockDevice);
myClass2.Stop();

Run is starting an operation on a hardware device, and Stop is of course trying to stop that operation (sending a reset-command and starting a timeout-timer).

Anyway I would like to test various post-conditions of calling Stop, but I would like NOT to have to call Run, because I am testing Stop - not Run! I would like something like this:

MyClass myClass = new MyClass(mockDevice);
myClass.Stop();
Assert.IsTrue(mockDevice.ResetCalled);

So far I only see one possible solution, and that is to create a TestableMyClass that inherits from MyClass, that makes it possible to set the right internal state of the MyClass instance before calling Stop. The problem with this solution is that I have to change my MyClass-implementation to have protected members in stead of private, and I don't like the idea of having to change the implementation in order to test it!

Should I use this solution, is there an error in my design, or is there a smarter way of doing this?

+2  A: 

As far as I see it, you are already testing Stop in the two ways in which it can be used (with and without a running operation). As long as the mockDevice is doing its job, it seem to me that you're testing it reasonably. Ideally you should be able to verify the commands sent to the device etc (which most mock frameworks will make simple).

Marc Gravell
So you think it is okay to just call Run, Stop, Assert?
toxvaerd
Yes, I think so. And also worth calling Stop without Run to check the required exception is thrown. Ultimately, it is not valid to call Stop without Run first...
Marc Gravell
+1  A: 

In this situation, personally, I would have two tests for this:

  1. Test without Run() being called first. I would test if it really throws the exception. I would also test if the post conditions are what I expect them to be.
  2. Test with Run() being called first. I would test only the post conditions, that I expect.

Those are the only two important uses of the method that have different behaviors - therefor I would test them both.

EDIT: I understand, why you don't want to call run, before stop - you think that if run fails, the test, that is supposed to only test stop method will most likely fail as well.

However, I would assume, that you also have test for the run method. This means, that when the tests, that test the behavior of run method pass - stop method tests must pass as well. If the run method tests fail, then the results of run method tests are undefined - they may or may not fail.

So, I'd say, don't be afraid to call other dependent methods in your tests, but make sure you test those dependent methods in separate tests.

Paulius Maruška
I am already testing the Stop-method that throws an exception, but I see your point!
toxvaerd
Thanks, for your answer, but I'm going to accept Marc Gravell's answer, as he was first :-)
toxvaerd
+1  A: 

It won't help your immediate problem, but I tend to favour mapping state to type rather than having objects with different modes.

IdleDevice idle = new IdleDevice(mockDevice);
RunningDevice running = idle.Run(myDatastructure);
running.Stop();

// This would not compile, as IdleDevice has no Stop method
IdleDevice idle = new IdleDevice(mockDevice);
idle.Stop();

If you can't compile impossible situations, you don't need to test them.

Pete Kirkham
I like that design! I will consider using that, but for now I will just test Stop followed by Run. Thanks
toxvaerd