Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing - how complex methods should be unit tested?

Let's assume, that I'm testing the following class (~pseudocode):

// (...)
public Result Process(Image image)
{
    Image image2 = PreprocessImage(image);
    PartialResult r1 = Process1(image2);
    PartialResult r2 = Process2(r1);
    Result result = FinalProcessing(r2);

    return result;
}

public Image PreprocessImage(Image image)
{
    Image tmp1 = Resize(image);
    Image tmp2 = Blur(tmp1);
    Image tmp3 = Median(tmp2);
    Image tmp4 = ExtractSpecificAreas(tmp3);

    return tmp4;
}

public Image Median(Image image)
{
     // Actual image median algorithm
}

For the problem to be more... problematic, let's assume, that results of most of these methods (eg, Process1, Process2, FinalProcessing, ExtractSpecificAreas) are, say, hardly predictable - for example there are some heuristic/decisive algorithms attempting to extract features from images: it may succeed in 90% situations and that's acceptable.

Which of these methods would you unit test? How would you unit test these methods except for invalid input / border conditions? How elementary shall (or how complex can) the method be for the unit test to make sense?

like image 249
Spook Avatar asked Mar 05 '13 08:03

Spook


People also ask

Should I unit test every method?

Every behavior should be covered by a unit test, but every method doesn't need its own unit test. Many developers don't test get and set methods, because a method that does nothing but get or set an attribute value is so simple that it is considered immune to failure.

What should be tested in unit testing?

The purpose of a unit test in software engineering is to verify the behavior of a relatively small piece of software, independently from other parts. Unit tests are narrow in scope, and allow us to cover all cases, ensuring that every single part works correctly.

How many types of methods we can test by using unit testing?

There are 2 types of Unit Testing: Manual, and Automated.

Which method is used for testing the unit testing?

Unit tests can be performed manually or automated. Those employing a manual method may have an instinctual document made detailing each step in the process; however, automated testing is the more common method to unit tests. Automated approaches commonly use a testing framework to develop test cases.


2 Answers

The general rule for unit tests is to test the smallest possible piece that you can test. A good rule is that each test should exercise exactly a single method from a public API.

That means it should only execute this method and no other, not even transiently. So if you want to test foo() and it calls bar(), then you should mock bar() instead of testing it also. Calling the internal, private method baz() would be OK, though.

If your method calls hundreds of internal methods, that calls for refactoring.

The reasoning is that a failure in a unit test should point you to the exact location of the problem. If you would unit test main(), then a failure would just tell you that there is a bug somewhere in the code of your project. If you unit test, say, String.length() and that test fails, you know pretty exactly where the bug must be.

This also answers your question: You have methods which return an unpredictable result. Mocking them would allow you to return always a known good/bad result, so you can test the method which does something with those results properly.

For the unpredictable methods, you will have to find similar strategies. I'm assuming here that you have neural networks somewhere which are trained, for example. So a test could be to pass some training images to the method N times until you're confident that the images are correctly sorted 90% of the time.

Again you should be able to split those methods into predictable and unpredictable parts which you can then test with mocking or statistical analysis.

Two great mock frameworks are Mockito and PowerMock.

like image 174
Aaron Digulla Avatar answered Sep 28 '22 00:09

Aaron Digulla


I think Aaron Digulla already pointed out what's most important: Test the smallest possible pieces and use mock objects.

But let me add one more thing: You may also want to test your overall application, i.e. whether the small pieces are working together nicely (this would be integration testing rather than unit testing, but anyway - you should do both). To test heuristic algorithms, I found it useful to start with an easy task to solve - in your case that would be sort of an "easy" image. This, of course, only gives you a baseline, it doesn't guarantee that it works in 90% situtations. But anyway it is helpful during development, and you could always enhance your (integration) test suite with more realistic samples if you want.

like image 36
claasz Avatar answered Sep 27 '22 22:09

claasz