Test a composite object when components have already been tested & # 8594; redundantly?

I have a general question, illustrated with a concrete example. How many would you recommend testing compound objects when all component objects have already been tested?

As a specific example, consider the NullTerminatedStringReader below. It reads a zero-terminated string from the byte buffer. To do this, use the Javas Charset decoder.

Of course I want to test my NullTerminatedStringReader. It should be able to read all types of strings, such as UTF8, UTF16, ASCII, etc.

Imagine that I wrote CharsetDecoder and verified that it will decrypt characters from all possible possible encodings. It is REALLY well tested and tried, and I have no doubt that it works. Now I am writing a NullTerminatedStringReader that uses a CharsetDecoder. In theory, I want NullTerminatedStringReader to be able to process all encoding strings that CharsetDecoder can decode. If I used TDD, I would like to manage my design, so I would write a lot of tests testing each encoding decoder for NullTerminatedStringReader:

... void testNullTerminatedStringReaderCanDecodeUTF8String() void testNullTerminatedStringReaderCanDecodeASCIIString() ... 

But this seems superfluous, 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 tests for the NullTerminatedStringReader, how can I manage this design to support all of these decoding? Am I testing at the wrong level for NullTerminatedStringReader? If I don't do tests, this also seems to be missing, because in theory I know that NullTerminatedStringReader uses CharsetDecoder, and I know that all he does is add characters to form a string, so there is not much that can go here not this way. If CharsetDecoder works, then NullTerminatedStringReader. But what if he did not use CharsetDecoder - I think it is more understandable to assume that there is no information about the implementation of NullTerminatedStringReader, and then write tests, however this leads to what seems like redundant tests. Dillema? You are betting.

 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) {...} } 
+4
source share
2 answers

When testing a composite object, I usually check two things:

  • Does it support composite end-to-end use cases for which it is intended?
  • Are additional features added by the composite object used?

In general, I would not try to fully test sub-objects, because for this they must have their own test cases. those. you should assume that your own sub-objects work the same way you assume java.util.ArrayList works.

So, in your NullTerminatedStringReader example, I would probably only verify that it works with one or two alternative encodings (i.e. proves that it calls the correct CharsetDecoder) and hopes that CharsetDecoder has been tested well enough for other encodings to work.

+1
source

I think you can consider this situation as a kind of integration test. To handle complexity, you are modular. For this you

  • you need to know the contract of the component that you are reusing (the CharsetDecoder precondition and postcondition that you use in readChar) so that your NullTerminatedStringReader can use another component that executes the contract. But you do not need to know that you are using the implementation of CharsetDecoder.
  • You don’t need to re-test the functionality of the component that you are reusing: you can simply assume postconditions as long as you meet the prerequisites.
  • use these TDD prerequisites to control the design of the NullTerminatedStringReader, but you can assume that the postconditions persist. And use the postconditions for TDD to control your design for some implementation, for example. CharsetDecoder, if you still need to create it. But for this you can assume that the prerequisites will be fulfilled.
+1
source

Source: https://habr.com/ru/post/1399646/


All Articles