Examples
CodeUnitTestFirst is a good idea, but I didn't do that at the time. I'm currently migrating to ProgrammerTests (ne UnitTests).
Also I don't have years of programming experience. To say: just do the design right and it will be easy to test doesn't help very much. It might be true, but how do I do the design right?
The idea to split the tasks into one class that does the normal operation and one that does the conditional operation sound good. But what is normal and what is conditional? What about nested conditions? See UnitTestTrial.
I think the idea to work on the problem together is a good idea. I started a page: UnitTestTrial (or do you know a better name?) Please have a look and give your comments. -- MalteKroeger
Guidelines (posted by individuals; not necessarily "accepted practice")
StandardizeTestingPractice?:
example: one test case per class, named ClassNameTestCase one test method per public method, named testMethodName? one test method per private algorithm method, named testMethodName? in each test method, test good results and failures sometimes split test method into two: testMethodName? testMethodName?Failures sometimes, in addition to one test case per class, add test cases for special "inter-class" logicTestCollector
TestSink?
...I'm struggling with something similar, except my outgoing interface is a serial cable - bundle of laughs. I'd suggest (someone correct me here) that you can attach a dummy test sink to the outgoing interface. Then you call the original method. You can then use a sequence of assert statements to check both the internal state of the tested object and the state of the test sink, which would record which event method got called on it. A simple boolean would do.
Something like this (excuse the C++/COM hybrid):
interface Outgoing { void someMethod(int aParam); }; class testSink { public: int m_saveParam; void someMethod(aParam) { m_saveParam = aParam; } }; // somewhere else pTestedObject = new testedObject; pSink = new testSink; pTestedObject->attachSink(pSink); pTestedObject->someMethodThatCallsTheSink(); assert(pSink->m_savedParam == expectedResult);I'm experimenting with a similar paradigm for the serial line comms stuff I'm doing now. -- RogerLipscombe
I've had to do some similar things at times to unit test. For instance, in a distributed system where classes instantiate proxies to remote objects, I've had to dummy up and register imposters so that calls to the proxies resolve locally. I check their state in assertions just like you do. -- MichaelFeathers
UseStandardRefactoringRulesToMakeCodeEasyToTest?
...Don't know, we don't do that. We build our code to be well-factored, well-designed. Testing generally seems straightforward. I'd rarely if ever warp the code to make it testable - the warping should be in the scaffolding that tests, perhaps with some helper methods extended into the class being tested. -- rj
Ron- Perhaps you were a natural, or perhaps you have forgotten how hard it was, but I hear this request lots. My advice is to make lots of little classes and lots of little methods, and to (temporarily) ignore public and private. Once you get the objects behaving you can figure out how to narrow the interface. -- KentBeck
The question I heard was "how do you change your design so as to make it testable". IMO, if the design is in fact good, i.e. well-factored, lots of little classes and lots of little methods, it'll be quite easy enough to test 99 44/100% of the time. I can't think of a single place in C3 where the design is changed for testability. There might be proxies, private methods, amazing left-handed hook shots over the crowd ... but nothing at the design level. I think MF has it right: CodeUnitTestFirst and don't do anything you haven't tested. But what do I know?
All that said, your answer sounds like an answer, even if to me it sounds like "just do a good design, and it'll test just fine". -- rj
For me the whole trick is CodeUnitTestFirst. You only add what you can test and what you need. After doing that enough times, refactoring as you go, you build up a sense of what WellFactoredCode looks like.
It is funny how the question changes. Today, I don't ask myself how to design my code to make testing easier. Instead, I ask myself how I can write tests so that the simplest thing that passes them is correct and useful in my application. -- MichaelFeathers
An example of design for testability- MassimoArnoldi and I were programming a complex object- it had to make a complicated decision about whether to operate or not, and then it had to do a complicated operation. We spent a day experimenting and couldn't come up with the tests and the code we could live with.
The next day, we made an object that unconditionally did the complicated operation. It turned out to be a remarkably simple operation when we weren't trying to think about the conditions at the same time- easy to test and easy to write. Then we wrote an object just for the condition, which turned out to be quite simple to test and code when we weren't trying to think about the operation at the same time. Then we had the condition-checking object create and invoke an operation only if the condition held- we didn't even need a test for that.
The design we made, with separate classes for condition and operation, was not at all the design we would have made had we not been testing. Does that sound like DesignForTestability? -- KentBeck
Depends. Is the second design better even in the absence of testing? Sounds like it is. Did you have a stuffy nose the first day? ;->
Pay no attention to me, I'm having a bad week. You da man. -- rj
Questions
Q: How do you test a class that can't be tested by itself? For example I have a class where, when I call a method, the internal state is changed and a message according to the new internal state of the class is generated (handled by another class) and sent over an interface (yet another class). A UnitTest can call a method on the class. But the generated message is not given as return code, but passed to another class that actually generates the message and hands it to the interface to send the message. How can you tell the message generated is correct? The only way that comes to my mind is to write a second test class that replaces the class that generates the messages and check if the right message is generated. But since this second class is called by the code, how can I integrate that into an assertion?
A: My UnitTests test black box behavior. If you are creating a test for class A and you need to make a fixture that creates instances of classes A, B, and C to test A, then the assertions must be framed in terms of the interfaces of A, B, and C. Was I hearing the right question? -- MichaelFeathers
I think it would be very helpful if some of the UnitTest Experts write some more about how to write UnitTests and how to design your code so you can apply UnitTests easily. -- MalteKroeger
How about some unit testing patterns? There must be automated testing solutions that experts have encountered again and again. Anyone willing to start a new pattern category? -- MikeHowells
Folks, maybe I'm a bit thick, but I think this still needs a concise answer, please:
Suppose class A's method foo is under unit test. Class A does not return a value but instead performs its operation by invoking Class B's method bar.
Do I provide a stub for method bar or do I use the 'real' method? Opinions?
-- Ben Baron
If B "stands alone" well enough that it isn't hard for the unit test to make one, and if the effect of B.bar is easy to test for, then by all means use the real thing. Otherwise use a fake B.
see ShouldUnitTestsTestInteroperations
The beauty of test first is that it is self limiting, you write a test for a feature then make it work, and that's all you write. It also forces you to structure your code to make it easier to test (you had to write the test first after all). The outcome is that you tend to end up with a design that reduces coupling, because it exposes just enough of the class as an interface, breaks the system down into smaller parts, because that makes it easier to test. Voila! You do tend to end up with a lot of MockObjects (enhanced stubs) but that often leads to a better design anyway.
To change the design they have to modify some or all of the tests. Typically they just comment out the tests.
Omigawd.
Have them refactor the tests. The refactored tests will tell them if the refactored design no longer works in a way that removed tests won't. -- MattRickard
From: JavaUnit
The way I accomplished unit testing of a class is to have a main method in the class itself. In the main, instantiate that class, call its public method and see if expected results are returned. Presumably calling the public methods tests all the services that the class can and will deliver. Also, call the methods with different set of input and see if it crashes. This allow test for robustness.
The above approach would work if the class is stand-alone (above referred as self-contained). When in a c/s architecture, I often write a client site application (such as an applet or command prompted application)to test every valid network call to the server (i.e. the services that the server object provision).
-- WendyLiew, April 16, 1999
Wendy, when you say "see if the expected results are returned", do you mean that you examine them yourself and say yea or nay; or does the program check them and tell you yes it worked or no it didn't? The first way is GuruChecksOutput, the second way is CheckOutputAutomatically.
-- JohnFarrell
Although I'm perhaps merely caffeine-deprived this morning, I'm having trouble wrapping my head around how to think about what seems like an obvious test scenario.
What is the easiest way to validate that the unit under test is issuing the correct API calls (in the correct sequence) to the other units it collaborates with? For example, suppose I'm testing behavior that traverses a particular data structure, emitting a sequence of methods in response to each element encountered (as in a series of visitors walking a structure). The order of traversal (pre- and post-order, for example) is supposed to be under program control. My thought is to isolate the unit under test, drive it with several carefully designed structures, and verify that it emits the correct sequence of output methods to the correct receivers.
I can, of course, hack something together (my first thought is some sort of MockObject where the methods being called trace their calls onto a string log, and then compare the log with a known result). I wonder what this community does in such cases.
-- TomStambaugh
The MockObject solution is my first instinct too.