Reputation: 583
I've got a general question illustrated with a concrete example. How much would you recommend testing composite objects when all the component objects are already tested?
As a concrete example consider the NullTerminatedStringReader below. It reads, from a bytebuffer, a null terminated string. To do this it uses Javas Charset decoder.
I of course want to test my NullTerminatedStringReader. It should be able to read all kinds of strings like UTF8, UTF16, ASCII and so on.
Imagine I had written the CharsetDecoder and tested that it would decode characters from all kinds of possible charsets. It's REALLY well tested and tried and I have no doubt that it works. Now I write a NullTerminatedStringReader that uses the CharsetDecoder. In theory I want the NullTerminatedStringReader to be able to handle all strings of charsets that the CharsetDecoder can decode. If I was using TDD I would want to drive my design, so I would write a lot of tests testing each charset decoding for NullTerminatedStringReader:
...
void testNullTerminatedStringReaderCanDecodeUTF8String()
void testNullTerminatedStringReaderCanDecodeASCIIString()
...
But this seems redundant because in the test for CharsetDecoder I have all these tests:
...
void testCharsetDecoderCanDecodeUTF8Char()
void testCharsetDecoderCanDecodeASCIIChar()
...
I'm not sure what to do here because without the tests for NullTerminatedStringReader, how can I drive it's design to support all of these decodings? Am I testing on the wrong level for NullTerminatedStringReader? If I don't make the tests it also seems something is missing because in theory I know the NullTerminatedStringReader is using CharsetDecoder and I know that all it does is append chars to form a string, so there's not much that can go wrong here. If CharsetDecoder works so should NullTerminatedStringReader. But what if it didn't use CharsetDecoder - I think it is more clear to assume no knowledge of NullTerminatedStringReader's implementation and then write the tests, however this results in what seems like redundant tests.. dillema? You bet.
class NullTerminatedStringReader
{
private Charset charset;
public String read(ByteBuffer buffer)
{
StringBuilder sb = new StringBuilder();
while (true)
{
char charVal = readChar(buffer, charset.newDecoder()); // unicode char, possibly span several bytes
if (charVal == '\0')
break;
sb.append(charVal);
}
return sb.toString();
}
private char readChar(ByteBuffer buffer, CharsetDecoder decoder) {...}
}
Upvotes: 4
Views: 494
Reputation: 7457
I think you can consider this situation as some kind of integration test: To cope with complexity, you are modularizing. For this, you
Upvotes: 1
Reputation: 106361
When testing a composite object I generally just test for two things:
In general, I wouldn't try to test the sub-objects comprehensively as they should have their own test cases to do that. i.e. you should assume that your own sub-objects work, in the same way that you assume that java.util.ArrayList works.
So in your example of the NullTerminatedStringReader, I'd probably only test that it works with one or two alternative charsets (i.e. prove that it is calling the correct CharsetDecoder) and trust that the CharsetDecoder was well enough tested to work will all other charsets.
Upvotes: 1