Unit testing session variable in controller with spock - unit-testing

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'
}
}

Related

Grails - How do I unit test controller asynchronous promise?

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.

How to unit test logging error with Spock framework in groovy

So I have a class that has a method that logs a message:
class Car {
private Logger logger = LoggerFactory.getLogger(Car.class);
void startCar() {
logger.error("car stopped working");
}
}
How can I test that the error was logged using the spock testing framework?
class CarTest extends Specification {
def "test startCar"() {
given:
Car newCar = new Car();
when:
newCar.startCar();
then:
// HOW CAN I ASSERT THAT THE MESSAGE WAS LOGGED???
}
}
you could check for an invocation of error on the logger
#Grab(group='org.spockframework', module='spock-core', version='0.7-groovy-2.0')
#Grab(group='org.slf4j', module='slf4j-api', version='1.7.7')
#Grab(group='ch.qos.logback', module='logback-classic', version='1.1.2')
import org.slf4j.Logger
class MockLog extends spock.lang.Specification {
public class Car {
private Logger logger = org.slf4j.LoggerFactory.getLogger(Car.class);
void startCar() {
logger.error('car stopped working');
}
}
def "mock log"() {
given:
def car = new Car()
car.logger = Mock(Logger)
when:
car.startCar()
then:
1 * car.logger.error('car stopped working')
}
}
edit: Full example https://github.com/christoph-frick/spock-test-logging
My Loggers are private static final so I cannot use solution mentioned above and rather not use Reflection.
If you are using Spring, you have acces to OutputCaptureRule.
#Rule
OutputCaptureRule outputCaptureRule = new OutputCaptureRule()
def test(){
outputCaptureRule.getAll().contains("<your test output>")
}

How to write unit test for this controller method?

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
}
}

How to test file upload in Grails

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
}
}

Verification tests in Scala

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