Given an extended example from the Grails documentation (http://grails.org/doc/latest/guide/async.html#asyncRequests):
import static grails.async.Promises.*
class myController {
def myServiceWithLongRunningMethod
def index() {
tasks otherValue: {
// do hard work
myServiceWithLongRunningMethod.doSomething()
}
}
}
How do I create a Spock unit test for this?
import static grails.async.Promises.*
import org.grails.async.factory.*
import grails.async.*
import grails.test.mixin.TestFor
import spock.lang.Specification
#TestFor(MyController)
class MyControllerSpec extends Specification {
def mockMyServiceWithLongRunningMethod = Mock(MyServiceWithLongRunningMethod)
def setup() {
// not sure if I need this next line
// Grails docs suggests making Promises synchronous for testing
Promises.promiseFactory = new SynchronousPromiseFactory()
controller.myServiceWithLongRunningMethod = mockMyServiceWithLongRunningMethod
}
def cleanup() {
}
void "index calls myServiceWithLongRunningMethod.doSomething()"() {
when: 'index is called'
controller.index()
then: 'myServiceWithLongRunningMethod.doSomething() is called'
1 * mockMyServiceWithLongRunningMethod.doSomething()
}
}
I get the following error:
Failure: index calls myServiceWithLongRunningMethod.doSomething()(MyControllerSpec)
| groovy.lang.MissingPropertyException: No such property: tasks for class: MyLoadingController
I'm not sure what the tests should look like - it's clear that I need to do something to enable the test class to understand the tasks method provided by Promise.
Related
I want to control the concurrency of some of my specs using SBT tags.
For example, I don't want more than 1 test that uses the database to run at the same time.
With ScalaTest, I would do
#TagAnnotation("database")
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.TYPE})
public #interface DatabaseTest { }
#DatabaseTest
class MyDatabaseTest1 ...
#DatabaseTest
class MyDatabaseTest2 ...
and then in build.sbt,
concurrentRestrictions in Global += exclusiveGroups(Tag("database"))
Most tests to be executed in parallel, but MyDatabaseTest1 and MyDatabaseTest2 would not run at the same time as the other.
Can I do this with specs2?
I added the functionality myself. (Issue for built-in support: https://github.com/etorreborre/specs2/issues/470)
src/test/java/test/Tag.scala
First define an annotation to be used. (I believe this can only be done in Java.)
package test;
import java.lang.annotation.*;
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.TYPE})
public #interface Tag {
String name();
}
src/test/scala/test/TaggingFramework.scala
Then define an implementation of sbt.testing.Framework that wraps a Framework and adds tags for the annotations. (Note: This depends on org.scala-sbt:test-interface. If you are already pulling in specs2, it should be there already.)
package test
import java.lang.annotation.Annotation
import sbt.testing._
import scala.util.Try
class TaggingFramework(framework: Framework) extends Framework {
def fingerprints(): Array[Fingerprint] = framework.fingerprints()
def name = s"TaggingFramework(${framework.name})"
def runner(args: Array[String], remoteArgs: Array[String], testClassLoader: ClassLoader) = {
val runner = framework.runner(args, remoteArgs, testClassLoader)
println(runner)
new Runner {
def args() = runner.args()
def done() = runner.done()
def remoteArgs = runner.remoteArgs()
def tasks(taskDefs: Array[TaskDef]) = runner.tasks(taskDefs).map { task =>
new Task {
def execute(eventHandler: EventHandler, loggers: Array[Logger]) = task.execute(eventHandler, loggers)
def taskDef = task.taskDef
def tags = task.tags ++ {
val fingerprint = taskDef.fingerprint
Try {
val isModule = fingerprint.getClass.getMethod("isModule").invoke(fingerprint).asInstanceOf[Boolean]
val className = taskDef.fullyQualifiedName + (if (isModule) "$" else "")
println(testClassLoader.loadClass(className).getAnnotationsByType(classOf[Tag]).map(_.name).toSeq)
testClassLoader.loadClass(className).getAnnotationsByType(classOf[Tag]).map(_.name)
}.getOrElse(Array.empty)
}
}
}
}
}
}
project/TaggingTestFramework.scala
Then in the build definition, define a TaggingTestFramework subclass of sbt.TestFramework. This will load the TaggingFramework if it is present. Otherwise, it just uses the original framework.
import sbt.TestFramework
import sbt.testing._
import scala.language.existentials
import scala.util.Try
class TaggingTestFramework(testFramework: TestFramework) extends TestFramework() {
override def create(loader: ClassLoader, log: sbt.Logger) = testFramework.create(loader, log).map { framework =>
Try(
Class.forName("test.TaggingFramework", true, loader).asInstanceOf[Class[Framework]]
.getConstructor(classOf[Framework]).newInstance(framework)
).getOrElse(framework)
}
override def toString = s"TaggingTestFramework($testFramework)"
}
build.sbt
And wrap the testFrameworks.
testFrameworks := testFrameworks.value.map(new TaggingTestFramework(_))
This should mostly work any Scala or Java framework, including specs2.
src/test/scala/example/MySpec.scala
Finally, to use add a tag to a testing task, simply add the annotation to the class.
import org.specs2.mutable.Specification
import test.Tag
#Tag(name = "database")
class MySpec extends Specification ...
Note 1: This currently does not work with inheritance.
Note 2: SBT forked tests work very differently. This and many other testing features are not available for forked tests.
I am trying to test that a session variable is set up in a method in a controller using a unit test in a Grails controller but it is complaining about setting a readonly property:
Cannot set readonly property: session for class: MyController
I have something like this:
class MyController {
def settingSession = {
session.var1 = "hello world!"
}
}
and this would be my test:
class MyControllerUnitTest extends ControllerSpec {
def "My test with sessions"() {
when:
controller.settingSession()
then:
controller.session.var1 == "hello world!"
}
}
I guest that probably I should write an integration test but I would like to know if there is any possibility of doing this in a unit test.
The following test will pass with Grails 2.1.0
A controller:
// grails-app/controllers/demo/MyController.groovy
package demo
class MyController {
def settingSession() {
session.band = 'King Crimson'
}
}
A unit test:
// test/unit/demo/MyControllerTests.groovy
package demo
import grails.test.mixin.*
import org.junit.*
#TestFor(MyController)
class MyControllerTests {
void testSettingSession() {
controller.settingSession()
assert session.band == 'King Crimson'
}
}
If you are using Spock:
// test/unit/demo/MyControllerSpec.groovy
package demo
import grails.test.mixin.*
import spock.lang.Specification
#TestFor(MyController)
class MyControllerSpec extends Specification {
void 'test session'() {
when:
controller.settingSession()
then:
session.band == 'King Crimson'
}
}
I trying to learn grails unit testing, I having a method like
def getProductList(){
List<Product> products = productService.getSodaProductList();
render(view:"productList",model:[products:products])
}
I want to write test function to this using GrailsUnitTestCase
I tried like this
void testGetSodaProductList(){
def sodaProduct = new SodaProduct(productName:"Test Product",productDesc: "",price:10.0);
mockDomain(SodaProduct,[sodaProduct])
def controller = new SodaProductController();
mockController(controller)
def list = controller.getSodaProductList();
assertEquals(2,list.model.products.size())
}
But not working, can some suggest how to write this test function?
I generally use the following way for unit testing
Using spock:
import grails.test.mixin.Mock
import grails.test.mixin.TestFor
import spock.lang.Specification
#TestFor(SodaProductController)
#Mock([SodaProduct, ProductService])
class SodaProductControllerSpec extends Specification {
void testGetSodaProductList() {
when:
SodaProduct sodaProduct =
new SodaProduct(productName: "Test Product",
productDesc: "Desc", price: 10.0)
controller.getProductList()
then:
view == "/sodaProduct/productList"
model.products.size() == 2
}
}
Without spock:
import grails.test.mixin.Mock
import grails.test.mixin.TestFor
#TestFor(SodaProductController)
#Mock([SodaProduct, ProductService])
class SodaProductControllerTests {
void testGetSodaProductList() {
SodaProduct sodaProduct =
new SodaProduct(productName: "Test Product",
productDesc: "Desc", price: 10.0)
controller.getProductList()
assert view == "/sodaProduct/productList"
assert model.products.size() == 2
}
}
I have a controller that takes in a file as part of the parameter. I'm wondering how can I test this?
my controller action:
def save () {
def colorInstance = new Color(params.color)
CommonsMultipartFile file = request.getFile('color.filename')
fileUploadService.upload(colorInstance, file, "foldername")
if (requestInstance.save(flush: true)) {
withFormat {
html {redirect(action: "list") }
js {render "test"}
}
}
}
I've started with something like this:...
import org.junit.Before
import grails.test.mixin.Mock
import grails.test.mixin.TestFor
#TestFor(ColorController)
#Mock(Color)
class ColorControllerTests {
#Before
void setUp() {
controller.fileUploadService = new FileUploadService
}
}
Question
I can't figure out how to test the CommonsMultipartFile for file upload.
Also, this test case will sit in unit test folder. How can I execute it?
I am using Grails 2.4, and you can simply use GrailsMockMultipartFile and request.addFile method in your unit test.
This code works on Grails 2.4.4, with Spock testing framework:
Controller side:
class FileUploadController {
def upload() {
def multipartFile = request.getFile('requestParamName')
if (multipartFile.empty) {
flash.message = 'Error: file cannot be empty'
render(view: 'upload')
return
}
// do something now with your file
}
}
Unit test side:
import grails.test.mixin.TestFor
import org.codehaus.groovy.grails.plugins.testing.GrailsMockMultipartFile
import spock.lang.Specification
#TestFor(FileUploadController)
class FileUploadControllerSpec extends Specification {
void "upload should add flash error message if empty file in request"() {
given:
def multipartFile = new GrailsMockMultipartFile('requestParamName', 'someExcelFile.xls', 'application/vnd.ms-excel', new byte[0])
request.addFile(multipartFile)
when:
controller.upload()
then:
assertEquals('Error: file cannot be empty', flash.message)
}
}
Since the request will be multipart during file upload, the actual request servlet would be MultipartHttpServletRequest. For unit test case, mock the same and use it as the request in controller. On successful mocking you should be able to addFile in tests and getFile in action.
import org.junit.Before
import grails.test.mixin.Mock
import grails.test.mixin.TestFor
#TestFor(ColorController)
#Mock(Color)
class ColorControllerTests {
#Before
void setUp() {
controller.fileUploadService = new FileUploadService
//Mock MultipartHttpServletRequest somethign like below
controller.metaClass.request = mockFor(MultipartHttpServletRequest).createMock()
}
void testFileUpload(){
//Add a mock multipart file to request
controller.request.addFile(new MockMultipartFile('myFile', 'IronMan3.jpg', 'image/jpeg', "1234567" as byte[]))
//call the controller action
//assert response
}
}
The accepted answer did not work for me. The following code did:
import org.junit.Before
import grails.test.mixin.Mock
import grails.test.mixin.TestFor
import org.springframework.mock.web.MockMultipartHttpServletRequest
import org.springframework.mock.web.MockMultipartFile
#TestFor(ColorController)
class ColorControllerTests {
def mockRequest
#Before
void setUp() {
mockRequest = new MockMultipartHttpServletRequest()
controller.metaClass.request = mockRequest
// your service here
controller.fileUploadService = new FileUploadService
}
void testFileUpload(){
//Add a mock multipart file to request
mockRequest.addFile(new MockMultipartFile('myFile', 'IronMan3.jpg', 'image/jpeg', "1234567" as byte[]))
//call the controller action
//assert response
}
}
I want to make some verification in my test, but it never fails
import org.testng.annotations.Test
import org.specs.Specification
import org.specs.mock.Mockito
import org.mockito.Matchers._
class Tests extends Specification with Mockito{
class Foo {
def bar(){}
}
#Test def simplestTest() {
val t = mock[Foo]
t.bar()
there was one(t).bar() //pass
}
#Test def simplestFailTest() {
val t = mock[Foo]
there was one(t).bar() //pass
}
#Test def testFail() {
assert(false) //fails
}
}
I'm run it as TestNG tests. Where I'm wrong?
It doesn't seem that specs supports running tests with TestNG: http://code.google.com/p/specs/wiki/RunningSpecs