I want to write a unit test for my controller which uses multiple services inside it.
How can I use multiple mockFor() for services?
Tnx.
For example using spock for testing:
class ExampleControllerUnitSpec extends Specification {
def anyService
def anotherService
def setup() {
anyService = Mock(AnyService)
controller.anyService = anyService
anotherService = Mock(AnotherService)
controller.anotherService = anotherService
}
def "test"(){
when:
controller.action()
then:
1 * anyService.doSomething() >> "result"
3 * anotherService.doSomethingElse() >> "result2"
}
}
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 unit testing a Grails controller method that internally creates an user instance. User domain class uses the springSecurityService of the Spring Security plugin to encode the password before inserting it into the database.
Is there a way to mock that springSecurityService from my unit test in order to get rid of that error?
Failure: Create new individual member(MemberControllerSpec)
| java.lang.NullPointerException: Cannot invoke method encodePassword() on null object
Please find my unit test below.
#TestMixin(HibernateTestMixin)
#TestFor(MemberController)
#Domain([User, IndividualPerson])
class MemberControllerSpec extends Specification {
void "Create new individual member"() {
given:
UserDetailsService userDetailsService = Mock(UserDetailsService)
controller.userDetailsService = userDetailsService
def command = new IndividualPersonCommand()
command.username = 'scott#tiger.org'
command.password = 'What ever'
command.firstname = 'Scott'
command.lastname = 'Tiger'
command.dob = new Date()
command.email = command.username
command.phone = '89348'
command.street = 'A Street'
command.housenumber = '2'
command.postcode = '8888'
command.city = 'A City'
when:
request.method = 'POST'
controller.updateIndividualInstance(command)
then:
view == 'createInstance'
and:
1 * userDetailsService.loadUserByUsername(command.username) >> null
and:
IndividualPerson.count() == 1
and:
User.count() == 1
cleanup:
IndividualPerson.findAll()*.delete()
User.findAll()*.delete()
}
}
One way to mock a service is to use Groovy's MetaClass
import grails.test.mixin.Mock
import grails.plugin.springsecurity.SpringSecurityService
...
#Mock(SpringSecurityService)
class MemberControllerSpec extends Specification {
def setupSpec() {
SpringSecurityService.metaClass.encodePassword = { password -> password }
}
def cleanupSpec() {
SpringSecurityService.metaClass = null
}
....
In this example, the call to SpringSecurityService.encodePassword() will simply return the password in plain text.
An approach using Mocks is discussed here.
You can to use this code to encode password in User:
def beforeInsert() {
encodePassword()
}
def beforeUpdate() {
if (isDirty('password')) {
encodePassword()
}
}
protected void encodePassword() {
password = springSecurityService?.passwordEncoder ? springSecurityService.encodePassword(password) : password
}
When springSecurityService is null, encodePassword is not called and NPE is not raised
When you use controller unit test with spring security rest plugin in Grails v4/v3, if your controller method reference springSecurityService methods like 'athenticatedUser', there will be NullPointException, because springSecurityService is not autowired into the spring application context.
Add code like below, you can inject springSecurityService and mock it's methods.
class GuessControllerSpec extends Specification implements ControllerUnitTest<GuessController> {
#Override
Closure doWithSpring() {
return {
// mock method
SpringSecurityService.metaClass.getCurrentUser = {return new User()}
// inject into spring context
springSecurityService(SpringSecurityService)
}
}
...
}
I have the following lines of code
username = username.stripIndent()
user = User."${databaseInstance}".findByUsername(username)
if (user == null){
return "User does not exist"
}
I'm trying to unit test this functionality with:
def setup() {
def mockUser = Mock(User)
myClass.user = mockUser
}
void "userNotFoundGetUserInfo"(){
given:
myClass.databaseInstance = 'X'
_ * mockUser._ >> null
when:
def result = myClass.getUserInfo(username)
then:
result == "User does not exist"
}
but I keep getting an error of "No such property: X for class mypackage.User"
I realize this is because i'm mocking the "user" object and not the "User" class, so how do I get around the fact that my code is making a direct call to a domain class?
Use Grails built-in #Mock annotation instead of Spock's Mock() method. Go like:
#Mock(User)
class YourTestSpecification extends Specification {
def setup() {
myClass.user = new User()
}
}
#Mock is meant to mock Grails domain classes.
I have a Grails controller that expects an XML payload.
I fetch the XML payload like this in a Grails controller.
def xmlPayload = request.reader.text
That part works fine, but I'm struggling to mock this payload in a unit test.
I've tried both of the following, but the debugger is showing 'request.reader' to be null in both approaches.
Approach #1:
void "test controller method"(){
setup:
def mockBufferedReader = Mock( BufferedReader )
mockBufferedReader.getText() >> '<hello/>'
request.getReader() >> mockBufferedReader
....
Approach #2:
void "test controller method"(){
setup:
def mockBufferedReader = Mock( BufferedReader )
mockBufferedReader.getText() >> '<hello/>'
request.metaClass.getReader = { -> mockBufferedReader }
....
'request' in a unit test is a GrailsMockHttpServletRequest, so I presumed I could mock its methods like this (3rd line of both approaches), but so far no luck.
Thanks for any ideas.
You can do:
class EchoController {
def echo () {
render (request.reader.text)
}
}
#TestFor(EchoController)
class EchoSpec extends Specification {
def "echos XML data" () {
request.XML = '<hello/>'
when:
controller.echo ()
then:
response.text == '<hello/>'
}
}
See Testing XML and JSON Requests in Unit Testing Controllers.
If you only need to provide contents for a request, then you don't need to mock anything.
def "Spock works as expected"() {
given:
def request = new GrailsMockHttpServletRequest(content: '<hello/>')
when:
def result = request.getReader().getText()
then:
result == '<hello/>'
}
One purpose of such Mock classes (as in Spring Test etc.) is to avoid explicit mocking with external libraries.
I have a service class method in my grails porject which uses a helper class to fetch the response as xml. The xml is then send out as the response of the service class method.
ServiceClass:-
class ItemService{
def getItem(Number) {
def HelperClass helper = new HelperClass()
def responseXml = helper.getMessage(Number)
return responseXml
}
}
I writing a test case for this method. In my test case, i wish to mock
def responseXml = helper.getMessage(Number)
The test case that i have written so far is:
class ItemServiceTest extends GroovyTestCase {
public final void testFindItem(){
def service = new ItemService()
def xml = "<Item><Number>123</Number></Item>"
def mockJobServiceFactory = new MockFor(HelperClass)
mockJobServiceFactory.demand.getMessage{ def str ->
return xml
}
service.getItem().HelperClass = mockJobServiceFactory.proxyInstance()
def item = service.getItem()("123")
assertNotNull(item)
}
but still, the mock does not return the xml that I speicified in the test case.
Any problems that you see in the above approach?...Advance Thanks
When you mock objects with MockFor, you need to surround the code that uses the mock in a use closure. Try this:
def service = new ItemService()
def xml = "<Item><Number>123</Number></Item>"
def mockJobServiceFactory = new MockFor(HelperClass)
mockJobServiceFactory.demand.getMessage{ def str ->
return xml
}
mockJobServiceFactory.use {
def item = service.getItem()("123")
assertNotNull(item)
}