How to test file upload in Grails - unit-testing

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

Related

Mocking a http response in kotlin

Currently I am working on a hobby project with that I want to learn a bit about kotlin.
I implemented an object that makes HTTP get requests and returns the Json object from the response.
What I'm struggeling with is the mocking of the response or the http framework in my tests.
I think if the framework would provide a class, I could manage the mocking. But as it only provides functions like khttp.get(), I'm a bit confused how to mock that.
Can someone help me, please? :)
Thanks!
The HTTPClient Class:
package dao.http.HTTPClient
import khttp.get
import org.json.JSONObject
import java.net.URLDecoder
class HTTPClient {
fun getClient(): HTTPClient {
return this
}
fun httpRequestGET(url: String): JSONObject {
val r = get(url)
return r.jsonObject
}
}
And the related test Class
import dao.http.HTTPClient
import io.mockk.every
import io.mockk.spyk
import org.hamcrest.MatcherAssert.assertThat
import org.json.JSONObject
import org.junit.jupiter.api.Test
import org.hamcrest.CoreMatchers.`is` as Is
import khttp.responses.GenericResponse
class HTTPClientTest {
#Test
fun testHTTPRequestGET() {
val http_get = spyk(khttp.get( "https://somepage.com/wp-json/tsapi/v1/user/ts/isregistered/12323"))
val httpClient = HTTPClient()
var expectedAnswer: JSONObject = JSONObject("""{"uid":"1","user":"user","is_registered":"true"}""")
every { http_get } returns GenericResponse()
var url = "https://somepage.com/wp-json/tsapi/v1/user/ts/isregistered/12323"
var actualAnswer = httpClient.httpRequestGET(url)
assertThat(actualAnswer.get("user"), Is(expectedAnswer.get("user")))
}
}
you can use it like this:
#Test
fun test() {
mockkStatic("khttp.KHttp")
verify { khttp.get(any()) }
verify(exactly = 1) { khttp.get(url = "http://google.com") }
}

Unit testing with dart's shelf_rest

I'm trying to test a Dart REST app run on shelf_rest. Assuming a setup similar to the shelf_rest example, how can one test the configured routes without actually running an HTTP server?
import 'package:shelf/shelf.dart';
import 'package:shelf/shelf_io.dart' as io;
import 'package:shelf_rest/shelf_rest.dart';
void main() {
var myRouter = router()
..get('/accounts/{accountId}', (Request request) {
var account = new Account.build(accountId: getPathParameter(request, 'accountId'));
return new Response.ok(JSON.encode(account));
});
io.serve(myRouter.handler, 'localhost', 8080);
}
class Account {
final String accountId;
Account.build({this.accountId});
Account.fromJson(Map json) : this.accountId = json['accountId'];
Map toJson() => {'accountId': accountId};
}
class AccountResource {
#Get('{accountId}')
Account find(String accountId) => new Account.build(accountId: accountId);
}
Without getting into too much additional logic, how could the GET account endpoint be unit tested? Some basic tests I'd like to run would be:
GET /accounts/123 returns 200
GET /accounts/bogus returns 404
To create a unit test (i.e. without a running server) then you need to split myRouter outside of the main function and put it in a file in the lib dir. e.g
import 'dart:convert';
import 'package:shelf/shelf.dart';
import 'package:shelf_rest/shelf_rest.dart';
var myRouter = router()
..get('/accounts/{accountId}', (Request request) {
var account =
new Account.build(accountId: getPathParameter(request, 'accountId'));
return new Response.ok(JSON.encode(account));
});
class Account {
final String accountId;
Account.build({this.accountId});
Account.fromJson(Map json) : this.accountId = json['accountId'];
Map toJson() => {'accountId': accountId};
}
Then create a test file in the test directory and test like
import 'package:soQshelf_rest/my_router.dart';
import 'package:test/test.dart';
import 'package:shelf/shelf.dart';
import 'dart:convert';
main() {
test('/account/{accountId} should return expected response', () async {
final Handler handler = myRouter.handler;
final Response response = await handler(
new Request('GET', Uri.parse('http://localhost:9999/accounts/123')));
expect(response.statusCode, equals(200));
expect(JSON.decode(await response.readAsString()),
equals({"accountId": "123"}));
});
}

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.

Unit testing session variable in controller with spock

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

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