Question

I have a companion object with a private method, like so:

package com.example.people

class Person(val age: Int)

object Person {
  private def transform(p: Person): Person = new Person(p.age + 1)
}

I would like to test this method, with something like:

class PersonSpec extends FlatSpec {

  "A Person" should "transform correctly" in {
    val p1 = new Person(1)
    val p2 = Person.transform(p1) // doesn't compile, because transform is private!
    assert( p2 === new Person(2) )
  }

}

Any help on having test code access private methods?

Actually, as it is written, I might be able to create a subclass of Person, but what if Person is declared as final or sealed?

Thanks!

Was it helpful?

Solution

I am in the middle when it comes to testing everything. I don't usually test everything, but sometimes it's really useful to be able to unit test a private function without having to mangle my code to make it possible. If you're using ScalaTest, you can use the PrivateMethodTester to do it.

import org.scalatest.{ FlatSpec, PrivateMethodTester }

class PersonSpec extends FlatSpec with PrivateMethodTester {

  "A Person" should "transform correctly" in {
      val p1 = new Person(1)
      val transform = PrivateMethod[Person]('transform)
      // We need to prepend the object before invokePrivate to ensure
      // the compiler can find the method with reflection
      assert(p2 === p1 invokePrivate transform(p1))
    }
  }

That may not be exactly what you want to do, but you get the idea.

OTHER TIPS

You could declare your method to be package private:

private[people] def transform(p: Person): Person = new Person(p.age + 1)

If you put PersonSpec in the same package it will be able to access it.

I leave it to you to decide if it's really wise to unit test a private method :)

The need to unit-test private methods is a design smell.

Either you test them through your public API which is ok if they are small and just helper methods - or, which is more likely, it contains different logic/responsibility and should be moved to another class that is used by delegation in the Person. Then you would test the public API of that class first.

See a related answer for more details.

Likely you can access it using Java/Scala reflection, but it is just a workaround for the design problem. Still, if you need to, see a related Java answer how to do that.

@jlegler's answer here helped me, but I still had some debugging to do before things worked, so I thought I'd write exactly what's needed for this here.

to test:

class A

object A {
  private def foo(c: C): B = {...}
}

use:

val theFuncion = PrivateMethod[B]('foo)
val result = A invokePrivate theFunction(c)

Note the locations of A, B

Personally, I say make everything public and just prepend with _ or __ to indicate that other devs shouldn't use it.

I realize this is Scala and not Python, but regardless, "We're all consenting adults here."

"Private" methods aren't actually private (for example) and certainly aren't secure, so why make life harder for what is essentially a social contract? Prepend and be done -- if another dev wants to go poking around in dark places, they either have a good reason or deserve what they get.

Generally speaking: if you want to effectively test your code, you first have to write it testable.

Scala implements the functional paradigm and extensively uses immutable objects by design, "case classes" are examples (my opinion: the Person class should be a case class).

Implementing the private methods make sense if objects has mutable state, in this case you might want to protect the state of the objects. But if objects are immutable, why implement methods as private? In your example, the method produces a copy of Person, for what reason do you want to make it private? I do not see any reason.

I suggest you think about this. Again, if you want to effectively test your code you have to write it testable.

a possible work around would be testing private method indirectly: testing a public method which calls the private method

I don't think that unit testing is about testing contract of the class - it is about testing simple functionality(unit).

Also I don't think that it is a good idea to make some methods public only to make them easily testable. I believe that keeping API as narrow as possible is a good way to help other developers to use your code(IDE will not suggest private methods) and understand contract.

Also we should not put everything in a single method. So sometimes we can put some logic into a private method.... and of course we want to test it as well. Testing it through the public API will increase complexity of you test.(other option is to move logic of the private method to another helper class and test it there..this class will not be used directly by developers and will not clutter up api)

Guys from scalatest ,I think, added PrivateMethodTester for a purpose.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top