My Play Application's Constructor takes an argument, how do I give a mocked argument at Spec Test? - scala

If my play application has something like this:
class Foo() extends Bar {}
class Application #Inject (f: Foo) extends Controller {
def index = Action { OK("Hi, Foo App") }
}
How do I change my spec test to accept MockedFoo class?
#RunWith(classOf[JUnitRunner])
class MockedFoo() extends Bar {}
class ApplicationTest(implicit ee: ExecutionEnv) extends Specification {
"Sending a GET request to index " should {
"Respond with OK " in new WithApplication { //######## Inject MockedFoo
val response = route(app, FakeRequest(GET, "/")).get
status(response) mustEqual OK
}
}
}
Thanks for the help:

Copying from my own Gist: https://gist.github.com/rethab/01fde763d10f29273d43
First, create a helper class for convenience:
class WithFancyApp(lang: Lang = Lang.defaultLang,
overrideModules: Seq[GuiceableModule] = Seq()) extends
WithApplication(
app =
new GuiceApplicationBuilder()
.in(Environment(new File("."), getClass.getClassLoader, Mode.Test))
.loadConfig(env => Configuration.load(env))
.overrides(overrideModules:_*)
.bindings()
.build
) {
implicit def messages: Messages = Messages(lang, app.injector.instanceOf[MessagesApi])
}
Usage:
"use the overridden bindigs" in new WithFancyApp(
overrideModules = Seq(bind[MyInterface].to[MyImplementation])
) {
// test stuff with all regular bindings plus the ones from above
}

Related

Why does it matter what order I mix in TestSuiteMixIn traits in scalatest suites?

I created the following fixtures:
trait DatabaseFixture extends TestSuiteMixin { this: TestSuite =>
// Just setting up a test database
val cpds = new ComboPooledDataSource
val url : URL = getClass.getResource( "c3p0.properties" )
val db = Database.forDataSource(cpds, Some(50))
val users = Schema.users
val instances = Schema.instances
Await.result(db.run( DBIO.seq(
users.schema.create,
) ), 3 seconds )
abstract override def withFixture(test: NoArgTest): Outcome = {
try super.withFixture(test)
finally cpds.close()
}
}
trait UserControllerFixture extends DatabaseFixture with ScalatraSuite { this: TestSuite =>
addServlet( new UserController(db), "/user/*" )
abstract override def withFixture(test: NoArgTest): Outcome = {
super.withFixture( test )
}
}
Here is the first way I mixed them in to a test suite:
class UserControllerTestSuite extends DatabaseFixture with ScalatraSuite with FlatSpecLike with Matchers {
"POST to /user/add" should "return 201 for created" in {
post( "/instance/add" ) {
status shouldBe 201
}
}
}
This failed to compile with the following error: method withFixture in trait TestSuite of type (test: UserControllerTestSuite.this.NoArgTest)org.scalatest.Outcome has weaker access privileges; it should be public
However, when I mixed the fixtures in after the other scalatest traits, it compiled fine:
class UserControllerTestSuite extends ScalatraSuite with FlatSpecLike with Matchers with DatabaseFixture {
"POST to /user/add" should "return 201 for created" in {
post( "/instance/add" ) {
status shouldBe 201
}
}
}
What's going on here? What does it mean that withFixture() has "weaker access privileges"?
Mixins in Scala are scanned right to left. This is why DatabaseFixture is called before other traits in case where your code works.
So before when there was some other trait (TestSuite) before DatabaseFixture with withFixture method , it tried to override it "weaker access privilege", which means exactly what it says. You cannot override public method with private for example. It has to be the same priority or higher (public > protected in your case.)

The mock of my class isn't getting called

I have a HelperMethod class.
class HelperMethods {
def getUniqueID(): UUID = {
UUID.randomUUID()
}
def bucketIDFromEmail(email:String): Int = {
val bucketID= email(0).toInt
println("returning id "+bucketID+" for name "+email)
bucketID
}
}
And an object which has an instance of HelperMethods
package object utilities{
private val helper = new HelperMethods()
def getUniqueID(): UUID = helper.getUniqueID()
def bucketIDFromEmail(email:String): Int = helper.bucketIDFromEmail(email)
}
I wrote a spec to test that my mock works correctly.
class UserControllerUnitSpec extends PlaySpec {
val mockHelperMethods = mock(classOf[HelperMethods])
when(mockHelperMethods.getUniqueID()).thenReturn(UUID.fromString("87ea52b7-0a70-438f-81ff-b69ab9e57210"))
when(mockHelperMethods.bucketIDFromEmail(ArgumentMatchers.any[String])).thenReturn(1)
"mocking helper class " should {
"work" in {
val bucketId = utilities.bucketIDFromEmail("t#t.com")
println("user keys are " + userKeys)
val id: UUID = utilities.getUniqueID()
println("got id " + userKeys)
bucketId mustBe 1
id mustBe UUID.fromString("87ea52b7-0a70-438f-81ff-b69ab9e57210")
}
}
}
the test fails with reason 116 was not equal to 1. This corresponds to line
bucketId mustBe 1 in the spec. I can see the print returning id 116 for name t#t.com. I shouldn't see it as I am trying to mock this class. I suspect that it could be because the utilities object is getting created before the statement val mockHelperMethods = mock(classOf[HelperMethods]) in the spec.
Question 2- Is there a way to mock HelperMethods and make utilities use the mocked class?
You have mocked HelperMethods but not utilities.
Question 2- Is there a way to mock HelperMethods and make utilities use the mocked class?
It is not possible to mock an object.
If you want, you have to extract the behavior in a trait.
Here is a solution that would work:
package utils
// move the behavior to a trait:
trait UtitilitiesTrait {
private[utils] def helper = new HelperMethods()
def getUniqueID(): UUID = helper.getUniqueID()
def bucketIDFromEmail(email: String): Int = helper.bucketIDFromEmail(email)
}
// provide an object for real use
object Utilities extends UtitilitiesTrait
// override helper for test mock
object TestUtilities extends UtitilitiesTrait {
private[utils] override def helper = mock(classOf[HelperMethods])
}
And here is your test:
class UserControllerUnitSpec extends PlaySpec {
val mockHelperMethods = mock(classOf[HelperMethods])
object TestUtilities extends UtitilitiesTrait {
private[utils] override def helper = mockHelperMethods
}
when(mockHelperMethods.getUniqueID()).thenReturn(UUID.fromString("87ea52b7-0a70-438f-81ff-b69ab9e57210"))
when(mockHelperMethods.bucketIDFromEmail(ArgumentMatchers.any[String])).thenReturn(1)
"mocking helper class " should {
"work" in {
val bucketId = TestUtilities.bucketIDFromEmail("t#t.com")
println("user keys are " + userKeys)
val id: UUID = TestUtilities.getUniqueID()
println("got id " + userKeys)
bucketId mustBe 1
id mustBe UUID.fromString("87ea52b7-0a70-438f-81ff-b69ab9e57210")
}
}
}
The typical pattern that enables mocking objects used internally is to inject them, or at least provide a way to inject an alternate.
Since Utilities is an object, you can't inject using a constructor. You could still introduce a setter method.
If you'd like to discourage use of the setter for anything other than unit tests, make it package-private, and you might also prefix the name with "qa":
private[utils] def qaSetHelperMethods(qaHelper: HelperMethods): Unit

How to inject Configuration instance to scalatest?

I want to inject Configuration instance in one of my testing classes, I extend my test class with ConfiguredApp and injected the Configuration, it looks like this:
#DoNotDiscover()
class MyApiServiceSpec extends FreeSpec with ScalaFutures with ConfiguredApp {
implicit val formats = DefaultFormats
implicit val exec = global
lazy val configuration = app.injector.instanceOf[Configuration]
"Global test" - {
"testcase 1" in {
Server.withRouter() {
case GET(p"/get/data") => Action { request =>
Results.Ok()
}
} { implicit port =>
WsTestClient.withClient { implicit client =>
val service = new MyApiService {
override def config: Configuration = configuration
override val ws: WSClient = client
}
whenReady(service.getData()) { res =>
//i will test stuff here
}
}
}
}
}
}
(MyApiService is a trait)
Exception encountered when invoking run on a nested suite -
ConfiguredApp needs an Application value associated with key
"org.scalatestplus.play.app" in the config map. Did you forget to
annotate a nested suite with #DoNotDiscover?
java.lang.IllegalArgumentException: ConfiguredApp needs an Application
value associated with key "org.scalatestplus.play.app" in the config
map. Did you forget to annotate a nested suite with #DoNotDiscover?
someone have an idea why is that...?
thanks!333333
My answer is not answer to current question, but I want give some advice. If you want to write unit tests for controllers or some service, I would suggest to use a PlaySpec. In order to inject custom configuration for testing environment:
class MyControllerSpec extends PlaySpec with OneAppPerSuite {
val myConfigFile = new File("app/test/conf/application_test.conf")
val parsedConfig = ConfigFactory.parseFile(myConfigFile)
val configuration = ConfigFactory.load(parsedConfig)
implicit override lazy val app: Application = new GuiceApplicationBuilder()
.overrides(bind[Configuration].toInstance(Configuration(configuration)))
.build()
"MyController #index" should {
"should be open" in {
val result = route(app, FakeRequest(GET, controllers.routes.MyController.index().url)).get
status(result) mustBe OK
}
}
}
It seems that you tried to run this test alone. But with a ConfiguredAppyou must run this test with a Suite, like
class AcceptanceSpecSuite extends PlaySpec with GuiceOneAppPerSuite {
override def nestedSuites = Vector(new MyApiServiceSpec)
}
The injection looks ok.

Specs2 with Scaldi - wrong implicit injector being invoked

I'm trying to run a test with scaldi and specs2. In the test I need to override a StringManipulator function that uses an injected ProxyManipulator. The ProxyManipulator takes a string and returns its upper case in a Future. The replacement manipulator in the test returns a Future("Test Message").
Here is the StringManipulator class where the injection occurs:
class StringManipulator {
def manip (str : String) (implicit inj: Injector) : String = {
val prox = inject[ProxyManipulator]
Await.result(prox.manipulate(str), 1 second)
}
}
I'm using a package.object that contains the implicit injector:
import modules.MyModule
package object controllers {
implicit val appModule = new MyModule
}
And here is the specs2 test with the new binding:
#RunWith(classOf[JUnitRunner])
class StringManipScaldiSpec extends Specification {
class TestModule extends Module {
bind [ProxyManipulator] to new ProxyManipulator {
override def manipulate(name: String) = Future("Test Message")
}
}
"Application" should {
"do something" in {
val myTestModule = new TestModule
val str = "my string"
val stringMan = new StringManipulator() //(myTestModule)
stringMan.manip(str)(myTestModule) === "Test Message"
}
}
}
The problem is that when the test runs the class StringManipulator is still using the original Proxy Manipulator instead of the one passed in the TestModule. Any ideas?

Scala: Can I reproduce anonymous class creation with a factory method?

As far as I understand it, Scala creates an anonymous class if I create a class using the new keyword and follow the class name with a constructor:
class MyClass {
def doStuff() {
// ...
}
}
val mc = new MyClass {
doStuff()
}
The nice thing being that all the code in the constructor is in the scope of the new object.
Is there a way I can reproduce this syntax where the class is created by a factory method rather than the new keyword? i.e. make the following code work:
val mf = new MyFactory
val mc = mf.MyClass {
doStuff()
}
I can't find a way to do it but Scala has so much to it that this might be pretty easy!
Using an import as suggested by #Ricky below I can get:
val mf = MyFactory;
val mc = mf.MyClass
{
import mc._
doStuff()
}
(Where the blank line before the block is needed) but that code block is not a constructor.
You can do this, but you still have to keep the new keyword, and create the nested class as a path-dependent type:
class Bippy(x: Int) {
class Bop {
def getIt = x
}
}
val bip = new Bippy(7)
val bop = new bip.Bop
bop.getIt // yields 7
val bop2 = new bip.Bop{ override def getIt = 42 }
bop2.getIt // yields 42
I don't think it's possible. However, a common pattern is to add a parameter to factory methods which takes a function modifying the created object:
trait MyClass {
var name = ""
def doStuff():Unit
}
class Foo extends MyClass {
def doStuff() { println("FOO: " + name) }
}
trait MyClassFactory {
def make: MyClass
def apply( body: MyClass => Unit ) = {
val mc = make
body(mc)
mc
}
}
object FooFactory extends MyClassFactory {
def make = new Foo
}
You can then create and modify instance with a syntax close to your example:
val foo = FooFactory { f=>
f.name = "Joe"
f.doStuff
}
It sounds like you're just looking to mix in a trait. Instead of calling myFactoryMethod(classOf[Foo]] which ideally would do (if Scala permitted it):
new T {
override def toString = "My implementation here."
}
you can instead write
trait MyImplementation {
override def toString = "My implementation here."
}
new Foo with MyImplementation
However, if you are just looking to get the members of the new object accessible without qualification, remember you can import from any stable identifier:
val foo = new Bar
import foo._
println(baz) //where baz is a member of foo.