I’m working with a Scala 2 project. I have the following code:
package com.myproject.commands;
object MyCommand {
def execute(args: Map[String, String]) = {
//do some validations...
doRealStuff(args)
}
private[commands] def doRealStuff(args: Map[String, String]) = {
//real process...
}
}
Due to technical restrictions I cannot change the object
design to class
because it involves a refactor of the whole project, test re-definitions and exhaustive functional and regression testing so it’s not feasible for the time being.
I have to add some behavior that must run always at the end of the execute
command, no matter if doRealStuff
failed. I came up with a try/catch
:
package com.myproject.commands;
object MyCommand {
def execute(args: Map[String, String]) = {
var exception: Option[Throwable] = None
//do some validations...
try {
doRealStuff(args)
} catch (e) {
exception = Some(e)
//handle exception...
} finally {
finalSteps(args, exception)
}
}
private[commands] def doRealStuff(args: Map[String, String]) = {
//real process...
}
private def finalSteps(args: Map[String, String], exception: Option[Throwable) = {
//add exception data if exists
}
}
This works when making doRealStuff
method failing using a debugger and tweaking some variables or running another process that will make it fail. And on a testing env can also cover this case. But I’m required to add a unit test in our code to check this path. This means I need to mock the companion object MyCommand
. I tried using PowerMockito but hit a road block:
package com.myproject.commands;
@RunWith(classOf[PowerMockRunner])
@PrepareForTest(Array(classOf[MyCommand.type]))
class MyCommandSpec extends AnyFlatSpec with Matchers with MockitoSugar {
@Rule
def rule = new PowerMockRule()
"MyCommand" must "fail on doRealStuff" in {
// Arrange
PowerMockito.mockStatic(MyCommand.getClass)
when(MyCommand.doRealStuff(any())).thenThrow(new Exception("test"))
// Act
val thrown = the[Throwable] thrownBy MyCommand.execute(/* args... */)
// Assert
thrown mustBe a[Exception]
}
}
This fails here:
@PrepareForTest(Array(classOf[MyCommand.type]))
With compiler error message:
class type required but com.myproject.commands.MyCommand.type found
And if I change it to get the class as in the “Arrange” section
@PrepareForTest(Array(MyCommand.getClass))
I get this other error:
annotation argument needs to be a constant; found: MyCommand.getClass()
How can I solve this?
By the way, this is the definition of @PrepareForTest
from PowerMock (it’s in Java, just putting the relevant part)
public @interface PrepareForTest {
Class<?>[] value() default IndicateReloadClass.class;
}