1

I'm facing a real problem with my unit tests. I'm currently working on a 2 year old project, and I've been writing unit tests for 2 months. Because of the complexity of the code, most of the functions that need to be tested call from 5 to 15 others functions, and in each function, around 5 objects with 10 parameters are used. At the beginning, I was only testing simple basic functions with Junit and EasyMock, but now I'm working with this type of complex function, setting the mocks and their behaviors takes around 300 lines for each test case, which is way to long for me.

Do you guys have any alternatives solutions to tackle this issue ?

MatthiasDec
  • 145
  • 1
  • 11
  • 1
    You can probably take mocking complexity down by splitting your test into several tests, so that each sets up only some of the relevant mocks. Other than that - the alternative is to split the complex function into parts, but you can't properly do that until you write tests for how it must works, so you know if you broke anything by splitting it up. However, this is more of a discussion type question, that either too broad or straight up opinion driven - either way, works bad for this site. Try asking elsewhere, or add a more concrete example of the thing. – M. Prokhorov Feb 13 '20 at 15:19
  • Thanks for your comment. Splitting my tests seems like a good solution yes, i'll do that. – MatthiasDec Feb 14 '20 at 09:13
  • 1
    Consider to implement test helper functions to factor out common parts of your test cases. If there are similarities even only between groups of tests this can reduce the test code size. It is a beneficial technique in general, not only in your case, because properly named helper functions can improve the readability of the test code. – Dirk Herrmann Feb 14 '20 at 22:37

1 Answers1

2

First, make a distinction which dependencies are really bothering you. See https://stackoverflow.com/a/60196328/5747415 for a list of criteria what makes dependencies troublesome. Those dependencies which are not troublesome do not need to be mocked.

Second, if you have the possibility, try to re-design the code: Separate computation dominated code (code without troublesome dependencies) from interaction dominated code (code mostly dealing with calling other code). Now look at the code parts where you could achieve this separation perfectly: Of these code parts, test the code with computations (and possibly non-troublesome dependencies) with unit-testing - there is obviously no need for mocking here. The code that consists only of interactions you would test with integration testing, again without mocking.

Third, there will likely remain code parts where such a perfect separation is difficult and you are left with computations mixed with interactions. Here you may have to do the unit-testing with doubles. There are also for these cases some re-design strategies that can reduce the mocking effort. For example, concentrating accesses to certain dependencies in helper methods (for example, a helper method that performs the job of fetching, authenticating and decompressing some data): After such a re-design, instead of having to mock several dependencies (same example: to data base, authentication lib, compression lib) you only have to mock your helper function.

This strategy can save you a lot of effort for creation of doubles.

Dirk Herrmann
  • 5,550
  • 1
  • 21
  • 47
  • Thanks for your answer. Unfortunately, I don't have the possibility to re-design the code I'm testing, but your tips are really helpful, thanks ! – MatthiasDec Feb 14 '20 at 09:12