I'd like to test a Grails controller that is sending out emails using the grails Email plugin. I'm at a loss exactly how to mock the sendMail closure in order for interactions to work. Here's my latest version of the test code:
def 'controller should send a multipart email'() {
given: 'a mocked mailService'
controller.mailService = Mock(grails.plugin.mail.MailService)
controller.mailService.sendMail(*_) >> Mock(org.springframework.mail.MailMessage)
when:
controller.sendNow()
then:
1* _.multipart(true)
}
The controller code looks something like what you'd expect, e.g.:
def mailService
def sendNow() {
mailService.sendMail {
multipart true
to 'example#example.org'
from 'me#here.com'
subject 'a subject'
body 'a body'
}
}
If I run this test, I get 0 invocations of my multipart interaction instead of 1. The second line of the given: block seems suspicious to me, but if I try to mock a Closure instead of org.springframework.mail.MailMessage my test crashes. I should also mention that the controller itself works as expected (it couldn't wait for me to figure out the unit tests first).
Edited
Aha, looking at the code with a fresh mind a few hours later, I can see why the above code does not work; in order for me to catch multipart and other DSL calls, I would have to mock the closure itself, not the sendMail method (and I can't do that since the closure is defined inside the controller itself). What I probably can do is check the arguments to the sendMail method to see everything necessary was passed into it.
I was able to achieve this in Spock with the following:
def messageBuilder
def bodyParams
def setup(){
def mockMailService = new MockFor(MailService)
mockMailService.ignore.sendMail{ callable ->
messageBuilder = new MailMessageBuilder(null, new ConfigObject())
messageBuilder.metaClass.body = { Map params ->
bodyParams = params
}
callable.delegate = messageBuilder
callable.resolveStrategy = Closure.DELEGATE_FIRST
callable.call()
}
service.mailService = mockMailService.proxyInstance()
}
And an example test:
def "sendEmailReceipt_passesCorrectParams"(){
when:
def receiptItems = [] << [item: "item1", price: 100]
service.sendEmailReceipt(receiptItems, "some#email.com")
then:
messageBuilder.message.to[0] == "some#email.com"
messageBuilder.message.subject == "My subject"
bodyParams.view == "/mailtemplates/emailReceipt"
bodyParams.model.receiptItems == data
}
You can install the greenMail plugin, and use it in an integration test:
From the greenmail plugin home page:
import com.icegreen.greenmail.util.*
class GreenmailTests extends GroovyTestCase {
def mailService
def greenMail
void testSendMail() {
Map mail = [message:'hello world', from:'from#piragua.com', to:'to#piragua.com', subject:'subject']
mailService.sendMail {
to mail.to
from mail.from
subject mail.subject
body mail.message
}
assertEquals(1, greenMail.getReceivedMessages().length)
def message = greenMail.getReceivedMessages()[0]
assertEquals(mail.message, GreenMailUtil.getBody(message))
assertEquals(mail.from, GreenMailUtil.getAddressList(message.from))
assertEquals(mail.subject, message.subject)
}
void tearDown() {
greenMail.deleteAllMessages()
}
}
I'm not a Spock expert but you should be able to translate this junit test to spock style.
Source: http://grails.org/plugin/greenmail
Udpate, alternative by mocking sendMail
This is an answer to Gregor's update. In my opinion, you would have to mock the sendMail method, and inside this method have an stub that implements the different properties and methods that are used in the closure. Lets call it an evaluator. The you would initialize the closure's delegate to the evaluatro, and execute the closure. The evaluator should have the assertions. You see that I'm using more junit concepts here. I don't know how easily you can translate that into spock concepts. You probably would be able to us the behaviour checking facilities of spock.
class MailVerifier {
void multiPart(boolean v){
//...
}
void to(String address){
//...
}
boolean isVerified() {
//check internal state obtained by the appropriate invocation of the methods
}
}
def sendMail(Closure mailDefintion) {
def evaluator = createMailVerifier()
mailDefinition.delegate = evaluator
mailDefinition()
assert evaluator.verified
}
Take a look at plugin tests here: plugin integration test and here: plugin unit test. In my opinion it would be hard for you to mock all MailService dependencies - factory and builder that builds your mail message. I'd end up with testing only if my controller's sendNow is called.
Edit
I've found this answer. According to it you can try:
def 'controller should send a multipart email'() {
given: 'a mocked mailService'
def mockMailService = new Object()
def mockMessageBuilder = Mock(MessageBuilder)
mockMailService.metaClass.sendMail = { callable ->
callable.delegate = mockMessageBuilder
callable.resolveStrategy = Closure.DELEGATE_FIRST
callable.call()
}
controller.mailService = mockMailService
when:
controller.sendNow()
then:
1* mockMessageBuilder.multipart(true)
}
def mailService = Mock(MailService)
mockMailService.metaClass.sendMail = { ... your logic ... }
controller.mailService = mailService
Related
I've got pretty simple application that uses Jooby as web framework. Its class responsible for REST looks like this
class Sandbox : Kooby ({
path("/sandbox") {
get {
val environment = require(Config::class).getString("application.env")
"Current environment: $environment"
}
get ("/:name") {
val name = param("name")
"Auto response $name"
}
}
})
I want to write integration test for it. My test looks like this. I use spock and rest-assured. The thing is that I don't have the application running and want to run it using some kind of embedded server or whatever. How to do that?
My simple test looks like this
class SandboxTest extends Specification {
def "check current environment"() {
given:
def request = given()
when:
def response = request.when().get("/sandbox")
then:
response.then().statusCode(200) // for now 404
}
}
You need to look for before/after test (or class) hooks in Spock. In the before hook you start Jooby without blocking the thread:
app.start("server.join=false")
in the after hook:
app.stop();
Never used Spock but here is a small extension method for Spek:
fun SpecBody.jooby(app: Jooby, body: SpecBody.() -> Unit) {
beforeGroup {
app.start("server.join=false")
}
body()
afterGroup {
app.stop()
}
}
Finally from your test:
#RunWith(JUnitPlatform::class)
object AppTest : Spek({
jooby(App()) {
describe("Get with query parameter") {
given("queryParameter name=Kotlin") {
it("should return Hello Kotlin!") {
val name = "Kotlin"
given()
.queryParam("name", name)
.`when`()
.get("/")
.then()
.assertThat()
.statusCode(Status.OK.value())
.extract()
.asString()
.let {
assertEquals(it, "Hello $name!")
}
}
...
...
...
...
Maven Spek example
Gradle Spek example
This drives me crazy, I have 2 http requests in a sample application:
open class RestController : Controller() {
val api = Rest()
init {
api.baseURI = "http://127.0.0.1:5059/"
}
}
class PendingCtlr : RestController() {
fun load(): ObservableList<PendingEntity> {
val txt = api.get("pendings").list()
val temp = txt.toModel<PendingEntity>()
return temp.observable()
}
}
class ConfirmedCtrl : RestController() {
fun load(id: Long): ObservableList<ConfirmedEntity> {
val li= api.get("confirmeds").list()
val temp = li.toModel<ConfirmedEntity>()
return temp.observable()
}
}
The first one works, the second one doesn't even hit the application level, it gets rejected with 400 BadRequest by my backend (Werkzeug).
I see absolutely no difference in both functions, and I can call both routes from my Swagger, as well as from python as well as from curl! Could someone please advise at least where to look for debug?
EDIT: The problem was on server side -_- Solved
I´m implementing my test framework using scalatest and I think I made a mistake using this framework instead of Cucumber
I´m trying to use some sort of features as Scenario outline of cucumber to avoid break DRY
here my problem
feature("Features of mus client") {
scenario("GET message with mus client") {
Given("a Musin message")
val config: Properties = new Properties
config.put("method", "POST")
config.put("encoding", "UTF-8")
config.put("uri", "http://localhost:9083/musClient")
When("I make a request to f2e")
val response = HttpClientTest.request(config, createJSON(READ))
Then("The message it´s returned successfully")
assert(response != null)
}
scenario("POST message with mus client") {
Given("a Musin message")
val config: Properties = new Properties
config.put("method", "POST")
config.put("encoding", "UTF-8")
config.put("uri", "http://localhost:9083/musClient")
When("I make a request to f2e")
val response = HttpClientTest.request(config, createJSON(CREATE))
Then("The message it´s returned successfully")
assert(response != null)
}
As you can see I have two scenarios where the 99% it´s the same steps but a variable that change the request.
Any idea how to do this elegant and efficient in scalatest
And I'm one of those too who chose scalatest over cucumber, cucumber was too much for me(ME) to write the feature file, and then come back to scala/java file and change accordingly. Maintain two files. I actually played cucumber java, scala cucumber might be more fluent. Anyway, I am liking scalatest so far for all my unit testing, component testing and the flow testing.
In case like yours if the properties are common for multiple scenarios and you won't mutate inside scenarios then defining as common property would be fine, as below.
class E2E extends FeatureSpec with GivenWhenThen {
feature("Features of mus client") {
Given("http config")
val config: Properties = new Properties(){{
put("method", "POST") //you are doing POST in both case by the way
put("encoding", "UTF-8")
put("uri", "http://localhost:9083/musClient")
}}
scenario("GET message with mus client") {
When("I make a request to f2e")
val response = HttpClientTest.request(config, createJSON(READ))
Then("The message it´s returned successfully")
assert(response != null)
}
scenario("POST message with mus client") {
When("I make a request to f2e")
val response = HttpClientTest.request(config, createJSON(CREATE))
Then("The message it´s returned successfully")
assert(response != null)
}
}
}
But, You might also want to use property based testing for the only part that changes, property based check was very fluent and readable in spock framework.
property based check in scalatest would look like below where I am testing for two different input parameters. (you neeed import org.scalatest.prop.TableDrivenPropertyChecks._)
class TestE2E extends FeatureSpec with GivenWhenThen {
val requestResponse =
Table(
("request", "response"),
( "GET", "GET-something"),
( "POST", "POST-something")
)
feature("testMe") {
forAll (requestResponse) { (givenRequestFromTable: String, expectedResponseFromTable: String) =>
scenario("for input " + givenRequestFromTable) {
When("input is " + givenRequestFromTable)
val output = testMe(input = givenRequestFromTable)
Then("responseFromTable has something appended to it")
assert(output == expectedResponseFromTable)
}
}
}
def testMe(input: String) : String = {
input + "-something"
}
}
There would be two scenarios based on two given properties,
And for you, the tests would be something as below with property based, hope there's no compile error :)
import org.scalatest.prop.TableDrivenPropertyChecks._
import org.scalatest.prop.Tables.Table
import org.scalatest.{FeatureSpec, GivenWhenThen}
class PaulWritesSpecs extends FeatureSpec with GivenWhenThen {
val requestResponse =
Table(
("httpMethod", "requestType"),
("GET", READ),
("POST", CREATE))
feature("Features of mus client") {
forAll(requestResponse) { (httpMethod: String, requestType: String) => {
scenario(s"$httpMethod message with mus client") {
Given("http config")
val config: Properties = new Properties() {{
put("method", httpMethod)
put("encoding", "UTF-8")
put("uri", "http://localhost:9083/musClient")
}}
When("I make a request to f2e")
val response = HttpClientTest.request(config, createJSON(requestType))
Then("The message it´s returned successfully")
assert(response != null)
}
}
}
}
}
I'm working on getting a test case working with Play 2.1.1 and Specs2 and am running into an interesting problem. I create a FakeRequest to send to a Controller, but the function in the controller never gets called.
Here's the test code (slightly simplified, but with all the moving parts):
"controller" should {
"do something" in new WithApplication {
val controller = new MyController()
controller.main() {
new FakeRequest(
PUT,
routes.MyController.main().toString,
new FakeHeaders(Seq("Content-Type" -> Seq("text/xml"))),
AnyContentAsXml(<xml>xml</xml>)
)
}
}
And here's the main function in the controller (well, at least just the start of it):
def main() = Action(BodyParsers.parse.xml) { request =>
println("main")
}
This code never hits main. Strangely enough, though, if I make the FakeHeader with no parameters, and remove AnyContentAsXml, just sending the Xml Element to the controller, then it works:
new FakeRequest(
PUT,
routes.MyController.main().toString,
new FakeHeaders,
<xml>xml</xml>
)
Does anyone have any idea why this would happen?
Here is your test little modified showing two ways testing the controller. The reason AnyContentAsXml is not working for you because your testing is mixing two approaches together.
"one way" in new WithApplication {
val action = controllers.Application.main
val req: FakeRequest[scala.xml.NodeSeq] = new FakeRequest(
PUT,
"some url",
new FakeHeaders(Seq("Content-Type" -> Seq("text/xml"))),
<xml>xml</xml>
)
val x = action(req)
status(x) should beEqualTo(200)
}
"2nd way" in new WithApplication {
val Some(result) = route(new FakeRequest("PUT",
"/",
new FakeHeaders(Seq("Content-Type" -> Seq("text/xml"))),
AnyContentAsXml(<xml>xml</xml>)))
status(result) should beEqualTo(200)
}
}
In the second approach Play is take care of unpacking the xml for the BodyParser to use. And here is the controller:
def main = Action(BodyParsers.parse.xml) { request =>
println(">>>>>>>>>>>>>>>>>>> main")
Ok("")
}
first of all, i'm learning scala and new to the java world.
I want to create a console and run this console as a service that you could start and stop.
I was able to run a ConsoleReader into an Actor but i don't know how to stop properly the ConsoleReader.
Here is the code :
import eu.badmood.util.trace
import scala.actors.Actor._
import tools.jline.console.ConsoleReader
object Main {
def main(args:Array[String]){
//start the console
Console.start(message => {
//handle console inputs
message match {
case "exit" => Console.stop()
case _ => trace(message)
}
})
//try to stop the console after a time delay
Thread.sleep(2000)
Console.stop()
}
}
object Console {
private val consoleReader = new ConsoleReader()
private var running = false
def start(handler:(String)=>Unit){
running = true
actor{
while (running){
handler(consoleReader.readLine("\33[32m> \33[0m"))
}
}
}
def stop(){
//how to cancel an active call to ConsoleReader.readLine ?
running = false
}
}
I'm also looking for any advice concerning this code !
The underlying call to read a characters from the input is blocking. On non-Windows platform, it will use System.in.read() and on Windows it will use org.fusesource.jansi.internal.WindowsSupport.readByte.
So your challenge is to cause that blocking call to return when you want to stop your console service. See http://www.javaspecialists.eu/archive/Issue153.html and Is it possible to read from a InputStream with a timeout? for some ideas... Once you figure that out, have read return -1 when your console service stops, so that ConsoleReader thinks it's done. You'll need ConsoleReader to use your version of that call:
If you are on Windows, you'll probably need to override tools.jline.AnsiWindowsTerminal and use the ConsoleReader constructor that takes a Terminal (otherwise AnsiWindowsTerminal will just use WindowsSupport.readByte` directly)
On unix, there is one ConsoleReader constructor that takes an InputStream, you could provide your own wrapper around System.in
A few more thoughts:
There is a scala.Console object already, so for less confusion name yours differently.
System.in is a unique resource, so you probably need to ensure that only one caller uses Console.readLine at a time. Right now start will directly call readLine and multiple callers can call start. Probably the console service can readLine and maintain a list of handlers.
Assuming that ConsoleReader.readLine responds to thread interruption, you could rewrite Console to use a Thread which you could then interrupt to stop it.
object Console {
private val consoleReader = new ConsoleReader()
private var thread : Thread = _
def start(handler:(String)=>Unit) : Thread = {
thread = new Thread(new Runnable {
override def run() {
try {
while (true) {
handler(consoleReader.readLine("\33[32m> \33[0m"))
}
} catch {
case ie: InterruptedException =>
}
}
})
thread.start()
thread
}
def stop() {
thread.interrupt()
}
}
You may overwrite your ConsoleReader InputStream. IMHO this is reasonable well because of STDIN is a "slow" stream. Please improve example for your needs. This is only sketch, but it works:
def createReader() =
terminal.synchronized {
val reader = new ConsoleReader
terminal.enableEcho()
reader.setBellEnabled(false)
reader.setInput(new InputStreamWrapper(reader.getInput())) // turn on InterruptedException for InputStream.read
reader
}
with InputStream wrapper:
class InputStreamWrapper(is: InputStream, val timeout: Long = 50) extends FilterInputStream(is) {
#tailrec
final override def read(): Int = {
if (is.available() != 0)
is.read()
else {
Thread.sleep(timeout)
read()
}
}
}
P.S. I tried to use NIO - a lot of troubles with System.in (especially crossplatform). I returned to this variant. CPU load is near 0%. This is suitable for such interactive application.