Is there a per-test non-specific mock reset pattern using Scala+PlaySpec+Mockito? - scala

I'm writing a unit test suite for a Scala Play application and I'm wondering if there's anything analogous to java's
#Mock
private Foo foo;
#Autowired/InjectMocks
private Bar fixture;
#BeforeMethod
public void setUp() {
MockitoAnnotations.initMocks(this);
}
For auto-mocking the annotated class and resetting it after every test
Currently I'm settling for
TestClass extends PlaySpec with BeforeAndAfterEach
private val foo = mock[Foo]
override def fakeApplication(): Application =
new GuiceApplicationBuilder().overrides(bind[Foo].toInstance(foo)).build
override protected def beforeEach(): Unit = {
reset(foo)
}
A cursory attempt at using the java annotations in the scala test was not successful. My current approach works, I just want to make sure there's not a nicer one.

mockito-scala solves this problem from version 0.1.1, as it provides a trait (org.mockito.integrations.scalatest.ResetMocksAfterEachTest) that helps to automatically reset any existent mock after each test is run
The trait has to be mixed after org.mockito.MockitoSugar in order to work, otherwise your test will not compile
So your code would look like this
TestClass extends PlaySpec with MockitoSugar with ResetMocksAfterEachTest
private val foo = mock[Foo]
override def fakeApplication(): Application =
new GuiceApplicationBuilder().overrides(bind[Foo].toInstance(foo)).build
The main advantage being not having to remember to manually reset each one of the mocks...
If for some reason you want to have a mock that is not reset automatically while using this trait, then it should be
created via the companion object of org.mockito.MockitoSugar so is not tracked by this mechanism
Disclaimer: I'm a developer of that library

Related

Injecting Play Application for a Slick Database Service

This is regarding a Play 2.3 application that I am trying to introduce Guice into.
I have the following legacy code to Guicify and I reached this point
class DatabaseService {
def db: Database = DB(play.api.Play.current)
//More code below.
}
This class is injected in the class under test, say com.TestA.
When I run the test cases using a modified OneAppPerTest setup, I see ProvisionExceptions of the following kind.
Error injecting constructor, java.lang.RuntimeException: There is no started application
Is it because of the use of play.api.Play.current?
How do I fix this issue?
Additional Info
The overridden OneAppPerTest variant, uses the following logic
override def newAppForTest(testData: TestData): FakeApplication = {
new FakeApplication(
additionalConfiguration = additionalConfiguration,
withGlobal = Some(globalSettings)
)
}
where additionalConfiguration can be overridden by actual tests and globalSettings is where Guice is introduced within the framework
protected def globalSettings = {
new TestGlobalSettings {
val injector = Guice.createInjector(overriddenModules: _*)
override def getControllerInstance[A](controllerClass: Class[A]): A = {
injector.getInstance(controllerClass)
}
override def getInjector = {
injector
}
}
}
There are other test cases with a similar setup that work perfectly fine. I am able to inject mocks, test the classes. However, every test with this DatabaseService class is failing, because I can't inject it cleanly.
The issue is related to how Guice creates the objects and when. DatabaseService here had access to the current application, the current configuration. However, in my Global.scala, I had it injected before 'onStart' was actually called.
This implies that we are trying to access an application before it was properly initialized.
Making DatabaseService injection in the test class lazy helped avoid the error.

How to Test a Play Application that extends a custom trait

I'm having trouble writing tests for a mixin to my Play application that runs in it's own thread separate from play. I've tried over-writing WithApplication.provideApplication method with no luck. I get an inheriting conflicting methods error. (one from the real app "MyRunnableSystemWrapper", one from my mocked fake mixin called "MyMockedSystemWrapper").
execute(system) runs my system that is tested elsewhere and has sideaffects (connects to networked services, thus failing this test when such things are not available. Good news is I have a mocked service of my system wrapper that uses a system which does NOT have side affects and DB/Network calls are mocked out. However I do not know how to give THIS MOCKED version of my app to "WithApplication" test.
Reduced Code for clarity:
class Application extends Controller with MyRunnableSystemWrapper {
val pool: ExecutorService = Executors.newFixedThreadPool(1)
val system = new MyRunnableSystem() //system is abstract in MRSW ^^^ above
pool.execute(system)
def index = Action {
OK("HI")
}
}
My Test:
class MyAppTest(implicit ee: ExecutionEnv) extends Specification {
abstract class WithMyMockApp extends WithApplication {
def provideApplication = new controllers.Application with MyMockedSystemWrapper // This imports MyRunnableSystemWrapper
}
"Sending a GET request" should {
"Respond with OK" in new WithMyMockApp {
val response = route(app, FakeRequest(GET, "/")).get
status(response) mustEqual OK
}
}
}
If I'm not running my Runnable in the correct place and should be calling it somewhere else to make this testing easier, let me know!
You could inject your system wrapper instead of extending it
trait SystemWrapper {
def execute(system: RunnableSystem)
}
class MyRunnableSystemWrapper extends SystemWrapper {...}
class MyMockedSystemWrapper extends SystemWrapper {...}
class Application #Inject() (systemWrapper SystemWrapper) extends Controller {
Then you need to tell Guice which implementation of SystemWrapper you want for runtime and which one for test. One way of doing this is by using different Guice modules for runtime/test which you set in your .conf files.

Create an Instance of class which does DI via Playframework Guice Independently in Scala

I'm working on Playframework2.5 with play-slick and programs related to it such as batch.
current project structure is like
/rootPlayProject
/app
/controllers
/filters
/services
...
Modules
/core (sub-project - DAOs,services are placed here)
/batch (sub-project depends on core)
I'm using Guice DI almost everywhere include Database Access Object(DAO).
And interfaces in core are bound in Module placed in core which end up getting inherited by Module in root project.
Core Module(/rootPlayProject/core/CoreModule.scala)
class CoreModule extends AbstractModule {
override def configure() = {
bind(classOf[FooDAO]).to(classOf[FooDAOImpl])
....
}
}
Root Module(/rootPlayProject/Modules.scala)
class Module extends CoreModule {
override def configure() = {
super.configure()
bind(classOf[FooService]).to(classOf[FooServiceImpl])
}
}
This works pretty well as Playframework application though, I would like to use core module for batch programs and I would like to run the batches without playframework.
so far I tried something like this
object BatchA {
def main(args: Array[String]) = {
val injector = Guice.createInjector(new CoreModule)
val foo = injector.getInstance(classOf[FooDAO])
//do something with foo.
}
}
but since my DAO's requiring things Playframework create such as ExecutionContext,play.api.db.slick.DatabaseConfigProvider and #play.db.NamedDatabase, above code does not run.
My question is, How can I let those things get bound without play application builder?
Thanks in advance.
The answer depends on whether or not you want to actually decouple Play Framework from your DAOs.
Option 1: Don't Decouple
Your main method could simply have the following lines preceeding your val injector line:
val application = new GuiceApplicationBuilder()
.in(Environment(new File("."), this.getClass.getClassLoader, Mode.Prod))
.build
Play.start(application)
Option 2: Decouple
Or, you can provide injectable classes that can provide the ExecutionContext specific to the environment. If you want to inject the DatabaseConfigProvider, you will have to perform further abstractions to remove the direct dependency on Play. The annotation will follow the Play-specific implementation of the abstraction.
In the case of my own project where I encountered this scenario, I opted for Option 1, as the dependency on Play wasn't severe enough of an impact for me.
GuiceInjectorBuilder do the trick.
trait PlayInjector {
lazy val injector = new GuiceInjectorBuilder().configure(Configuration.load(Environment.simple(mode = Mode.Dev)))
.bindings(new BuiltinModule, new CoreModule, new SlickModule).disable(classOf[Application]).injector
def closeInjector = injector.instanceOf[DefaultApplicationLifecycle].stop
}
BuiltinModule binds Play basic modules such as ExecutionContext, ExecutionContextExecutor or ActorSystem.
You can make your own Module to bind only things you need to though, using BuiltinModule and disable classes you don't need is simpler.
how to use it
object Foo extends PlayInjector {
def main(args: Array[String]) = {
val foo = injector.instanceOf[FooDAO]
val bar = injector.instanceOf[BarDAO]
//do something
//when you finish things you want to do
closeInjector
}
}
Since some modules like PlaySlick uses ApplicationLifecycle.addStopHook to handle closing operation. It's safer to execute them instead of just call sys.exit()

How to run ConfigMapWrapperSuite?

I need to write an integration test and it requires starting a server executable. I want to make location of the server configurable, so that I could set it on my box and on integration server.
ConfigMapWrapperSuite seems to be doing exactly what I want:
#WrapWith(classOf[ConfigMapWrapperSuite])
class ConsulTest(configMap: ConfigMap) extends FlatSpec with ShouldMatchers {
val consulPath = configMap("consul.path")
"Consul" should "list keys under root" in {
...
}
But when I set my IDE (IntelliJ) to execute all tests in the project, I get an exception saying that constructor with Map parameter not found. Looking into source code of scalatest revealed:
final class ConfigMapWrapperSuite(clazz: Class[_ <: Suite]) extends Suite {
private lazy val wrappedSuite = {
val constructor = clazz.getConstructor(classOf[Map[_, _]])
constructor.newInstance(Map.empty)
}
So in contrary to what documentation says, suite must have constructor with a Map and not ConfigMap.
Ok, I changed constructor to take a Map[String,String] but now I get NoSuchElementException at val consulPath = configMap("consul.path"). Lookung up the stack down to ConfigMapWrapperSuite and I see that constructor.newInstance(Map.empty) WTF? So wrapped suite class is instantiated with empty map, and than another time, during the suite run with actual map of parameters? How do I suppose to get parameters if I'm given an empty map?
I looked up scalatest's unit tests. They are so rudimentary that actually retrieving a value from configMap is not performed.
I do not want to use ConfigMapFixture because it will make me initializing every single test with the same code.
So, how do I not only pass but also get global setting in test suite?
Scalatest version: 3.0.0-M15
Ok, answering my own question. ConfigMapWrapperSuite seems to be not used too much and essentially is broken.
Instead I've used BeforeAndAfterAllConfigMap as in here:
class ConsulTest extends FlatSpec with ShouldMatchers with OneInstancePerTest with BeforeAndAfterAllConfigMap {
var consulProcess: Process = null
override def beforeAll(conf: ConfigMap): Unit = {
consulProcess = Seq("bin/"+exe, "agent", "-advertise", "127.0.0.1", "-config-file", "bin/config.json").run()
}
override def afterAll(conf: ConfigMap): Unit = {
consulProcess.destroy()
}
You need override instance
#WrapWith(classOf[ConfigMapWrapperSuite])
class AcceptanceTest(configMap: Map[String, Any])
extends FlatSpec
with OneInstancePerTest {
override def newInstance = new AcceptanceTest(configMap)
}

How to do setup/teardown in specs2 when using "in new WithApplication"

I am using Specs2 with play 2.2.1 built with Scala 2.10.2 (running Java 1.7.0_51). I have been reading about how to do setup/teardown with Specs2. I have seen examples using the "After" trait as follows:
class Specs2Play extends org.specs2.mutable.Specification {
"this is the first example" in new SetupAndTeardownPasswordAccount {
println("testing")
}
}
trait SetupAndTeardownPasswordAccount extends org.specs2.mutable.After {
println("setup")
def after = println("teardown ")
}
This works fine, except that all of my tests are using "in new WithApplication". It seems what I need is to have an object which is both a "WithApplication" and an "After". Below does not compile, but is essentially what I want:
trait SetupAndTeardownPasswordAccount extends org.specs2.mutable.After with WithApplication
So, my question is, how do I add setup/teardown to my tests which are already using "in WithApplication"? My primary concern is that all of our tests make use of fake routing like this (so they need the With Application).
val aFakeRequest = FakeRequest(method, url).withHeaders(headers).withBody(jsonBody)
val Some(result) = play.api.test.Helpers.route(aFakeRequest)
result
This is the code for WithApplication:
abstract class WithApplication(val app: FakeApplication = FakeApplication()) extends Around with Scope {
implicit def implicitApp = app
override def around[T: AsResult](t: => T): Result = {
Helpers.running(app)(AsResult.effectively(t))
}
}
It's actually quite easy to modify this to suit your needs without creating a bunch of other traits. The missing piece here is the anonymous function t, which you provide the implementation for in your tests (using WithApplication). It would be nice to make WithApplication a little more robust to be able to execute arbitrary blocks of code before and after the tests, if necessary.
One approach could be to create a similar class to WithApplication that accepts two anonymous functions setup and teardown that both return Unit. All I really need to do is modify what's happening inside AsResult.effectively(t). To keep this simple, I'm going to remove the app parameter from the parameter list, and use FakeApplication always. You don't seem to be providing a different configuration, and it can always be added back.
abstract class WithEnv(setup: => Unit, teardown: => Unit) extends Around with Scope {
implicit def implicitApp = app
override def around[T: AsResult](t: => T): Result = {
Helpers.running(app)(AsResult.effectively{
setup
try {
t
} finally {
teardown
}
})
}
}
Instead of simply calling the anonymous function t, I first call setup, then t, then teardown. The try/finally block is important because failed tests in specs2 throw exceptions, and we want to be sure that teardown will be executed no matter what the outcome.
Now you can easily setup test environments using functions.
import java.nio.files.{Files, Paths}
def createFolder: Unit = Files.createDirectories(Paths.get("temp/test"))
def deleteFolder: Unit = Files.delete("temp/test")
"check if a file exists" in new WithEnv(createFolder, deleteFolder) {
Files.exists(Paths.get("temp/test")) must beTrue
}
(This might not compile, but you get the idea.)
If your after method doesn't need anything from the WithApplication trait you can mix in your specification the AfterExample trait and define the after behaviour for the whole spec:
import org.specs2.specification._
class Specs2Play extends org.specs2.mutable.Specification with AfterExample {
"this is the first example" in new SetupAndTeardownPasswordAccount {
pending("testing")
}
trait SetupAndTeardownPasswordAccount extends WithApplication
def after = println("cleanup")
}