10

Is there any way to test a nested function (ideally with ScalaTest)?

For example, is there a way to test g() in the below code:

def f() = {
  def g() = "a string!"
  g() + "– says g"
}
Aaron Yodaiken
  • 19,163
  • 32
  • 103
  • 184

2 Answers2

10

g is not visible outside of f, so I daresay no, at least not without reflection.

I think testing g would break the concept of unit testing, anyway, because you should never test implementation details but only public API behaviour. Tracking an error to a mistake in g is part of the debugging process if tests for f fail.

If testing g is important for you, define g as (protected) method outside of f. That might break your design, though.

Another idea would be to put calls to assert after the call of g in the original code. This will be executed during tests and raise an exception if the property does not hold, causing the test to fail. It will be there in regular code, too, but can be removed by the compiler as assert (and companions) are elidible (see e.g. here).

Raphael
  • 9,779
  • 5
  • 63
  • 94
  • 2
    +1: I completely agree. Since you can't *call* `g()`, you don't need to worry about it - so long as `f()` behaves correctly it doesn't matter what the details are. There's no conceptual difference to defining and then calling `g`, or just executing the code in-line; it's an internal book-keeping measure which is irrelevant to code correctness. `f` could work by getting unicorns to magically calculate the result; so long as the result was correct and arrived in a timely fashion (and with no visible external dependencies), it's not unit testing's job to peek under the hood. – Andrzej Doyle Mar 17 '11 at 12:24
  • 1
    @AndrzejDoyle but if I just want to speed up development (avoid debugging) and test everything step by step... I think this problem is similar to http://stackoverflow.com/questions/34571/whats-the-proper-way-to-test-a-class-with-private-methods-using-junit – ichaki5748 Sep 13 '13 at 19:10
  • 2
    I test drive my code. And so the tests aid me in refining logic even if it's not going to be part of a public contract. In this case, my tests are not about guarranteeing the contract, but a dev aid. I guess I can just develop the function outside of the function, then relocate it after finishing the logic. – chad Sep 03 '15 at 03:45
  • 1
    @Raphael How would testing a unit of code break the concept of unit testing? Isn't the point of unit testing to test every unit of code? (As opposed to black box testing, where you test only external behavior.) – aij Dec 21 '15 at 14:38
  • @aij Exposing a function that is private by design is what might break things. – Raphael Dec 25 '15 at 10:56
  • @Raphael Well, yes, that too, but you said, "I think testing g would break the concept of unit testing". If that's not actually what you mean, you might want to edit your answer... – aij Dec 25 '15 at 17:50
1

You could make method private[package-name] - still breaks design a bit, but keeps it private instead of protected.

Generally I agree with the fact that one should not test private methods, but if you are maintaining poorly written code...

private[example] def g() = "a string!"

def f() = {
  g() + "– says g"
}

Now test in same package (example) could test g()