0

I have a validation method like this

def validate(a, b, c, d, e, f): Boolean = {
  val rs1 = check1(a, b)
  val rs2 = check2(c, d)
  val rs3 = check3(e, f)

  rs1 && rs2 && rs3
}

I have tests for all of the smaller methods check1, check2, and check3 and I want to test the big method validate also. But to test it, I imagine I have to write tests for all of the cases like:

  • all 3 checks succeed
  • check1 fails
  • check2 fails
  • ...

not to mention I will have to provide suitable sets of parameters (a, b, ...).

So what is the best practice for this situation or should I just skip testing the validate method?

3

3 Answers 3

0

Test things that could go wrong. So maybe, writing tests for this method would not have much value. It is very simple code, and unlikely to be incorrect. The most likely source of errors is that you are passing the wrong arguments to the check() functions. If you are using a statically typed language, that risk is already reduced.

Note that a single test case (regardless of validation result) is sufficient to provide 100% statement, branch, and path coverage for this implementation of the validation() function when viewed in isolation. However, it does not provide full condition coverage. So writing at least one test case may be desirable. Maybe adding a second test case would also be good, so that you have one successful and one failing validation result.

Beyond that, testing for 100% condition coverage takes increasing amounts of effort for decreasing value. Unless correctness of the method is extremely important (e.g. a failure could cause permanent harm to users and/or would be very costly) this doesn't seem important. To test this method comprehensively, it may be desirable to rewrite your tests of checkX() functions as tests of the validate() function. This may result in less total effort than writing 3+1 additional tests where you have one test where all checks succeed, and one test per check where that check fails. Also, some people dislike white-box techniques like creating test cases to reach some coverage goal instead of using test cases to express requirements.

1

I have tests for all of the smaller methods check1, check2, and check3...

That is the cause of your current problems. check1 etc are implementation details of validate, so should only be tested via testing validate. So change those existing tests to use validate. That gives you that "suitable sets of parameters (a, b, ...)".

All that's then left to do is to test that it only validates when all checks pass.

2
  • 1
    Your point makes sense but if check1 will be used in other places (potentially) then shouldn't I keep testing check1?
    – Minh Thai
    Jun 5, 2018 at 9:03
  • @MinhThai, you are testing check1, via validate. If it's used elsewhere too, then test it via those places, too.
    – David Arno
    Jun 6, 2018 at 13:54
-2

I think that this Validate() method is potentially violating the Single Responsibility Principle. According to the SRP, "A class should have one reason to change". Here, we have three reasons to change. Thus, we are violating SRP. I think that's your main problem here.

To refactor this, I would extract check1() check2() and check3() into their own classes, unit test them separately, then inject them into the main validator class. After doing that, I would mock out Check1Validator, Check2Validator, and Check3Validator. The only thing to test now would be the invalid input of validate(), and the condition rs1 && rs2 && rs3.

3
  • I understand your setup but wouldn't that be the same situation? We still have validate receiving (a, b, c...) then calls 3 checks then finally do rs1 && rs2 && rs3. There must be always a place where we have to call those 3 checks and merge their results right?
    – Minh Thai
    Jun 6, 2018 at 3:19
  • This answer can be a good approach – but if you inject the check functions, you are introducing another point of fragility. Now we need to ensure that we are injecting the correct checks at runtime. Also, I don't think a single validate() method that calls various helper functions is a violation of the SRP.
    – amon
    Jun 6, 2018 at 9:21
  • @MinhThai, Not if you mock out the the checks. By mocking out, I mean you can use a mocking library to return a dummy value for check1(), check2(), and check3() whenever they are called. Then, you can test that the three validation methods were called properly with the right parameters, and what Validate() does with their return values. You don't care about testing them, because you are testing them separately. Jun 6, 2018 at 13:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.