How can I log test-specific infomation when implementing TestCaseExtension? - kotlintest

In a TestCaseExtension, I want to log test-specific information. At first sight, doing it like this seems to work:
import io.kotlintest.*
import io.kotlintest.extensions.SpecLevelExtension
import io.kotlintest.extensions.TestCaseExtension
import io.kotlintest.specs.DescribeSpec
class MySpec : DescribeSpec({
describe("bar") {
it("a") {}
it("b") {}
}
}) {
override fun extensions(): List<SpecLevelExtension> = listOf(MyExtension())
}
class MyExtension : TestCaseExtension {
override suspend fun intercept(
testCase: TestCase,
execute: suspend (TestCase, suspend (TestResult) -> Unit) -> Unit,
complete: suspend (TestResult) -> Unit
) {
execute(testCase) { testResult ->
if (testCase.type == TestType.Test) {
println(testCase.description.name)
}
complete(testResult)
}
}
}
In IntelliJ IDEA, the output for the first test is "Scenario: a" and the output for the second test is "Scenario: b". However, when changing describe("bar") to describe("foo"), the output for the first test becomes "Scenario: a[newline]Scenario: b", while the output for the second test becomes empty.
So, how can I properly assign logged information to each test? Maybe using println is not even the right choice?
io.kotlintest:kotlintest-runner-junit5:3.2.1
JDK 10.0.2
IntelliJ IDEA 2018.3.2 (Community Edition)

Related

integration testing of Jooby application using Spock

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

Which RxJava scheduler does doOnDispose() use?

I have an Rxjava assembly something like this:
val observable = dialogPresenter.show(dialogData, viewContext!!)
.subscribeOn(mainScheduler)
.observeOn(mainScheduler)
.doOnDispose(dialogData::dismiss)
When the subscription is disposed, the call to dialogData::dismiss is happening on a thread other than that used by mainScheduler, which as the name implies uses the main thread for the particular platform the code is running on. The Javadoc for doOnDispose() says it does not operate by default on a particular scheduler, but I would have expected it to use either the subscribeOn() scheduler or the observeOn scheduler. So what does it use and is there an elegant way of controlling which thread it is executed on?
Even though the question was asked more than 3 years ago, let me contribute because I just encountered a similar issue.
package com.example.sample4
import android.os.Bundle
import android.util.Log
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
import io.reactivex.Observable
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
class MainActivity : AppCompatActivity() {
private lateinit var disposable: Disposable
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
findViewById<Button>(R.id.start).setOnClickListener {
disposable = Observable.just(1, 2, 3, 4, 5)
.subscribeOn(Schedulers.io())
.flatMap { i ->
Observable.fromCallable {
Thread.sleep(1_000L)
if (i == 3) {
disposable.dispose()
}
i
}
}
.map { it * 2 }
.observeOn(Schedulers.single())
.doOnNext {
Log.d("SampleApp", "val=$it on ${Thread.currentThread().name}")
}
.doOnDispose {
Log.d("SampleApp", "disposed on ${Thread.currentThread().name}")
}
.unsubscribeOn(Schedulers.computation())
.subscribe {
println(it)
}
}
}
}
Log:
2022-01-17 16:34:35.585 27458-27505/com.example.sample4 D/SampleApp: val=2 on RxSingleScheduler-1
2022-01-17 16:34:36.587 27458-27505/com.example.sample4 D/SampleApp: val=4 on RxSingleScheduler-1
2022-01-17 16:34:37.590 27458-27505/com.example.sample4 D/SampleApp: val=6 on RxSingleScheduler-1
2022-01-17 16:34:37.590 27458-27506/com.example.sample4 D/SampleApp: disposed on RxComputationThreadPool-1
As you can see, the scheduler used in doOnDispose is provided in unsubscribeOn. And it's important to put unsubscribeOn last.

cannot get rest service

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

spray and actor non deterministic tests

Helo,
at the beginning i wold like to apologize for my english :)
akka=2.3.6
spray=1.3.2
scalatest=2.2.1
I encountered strange behavior of teting routes, which asks actors in handleWith directive,
I've route with handleWith directive
pathPrefix("firstPath") {
pathEnd {
get(complete("Hello from this api")) ~
post(handleWith { (data: Data) =>{ println("receiving data")
(dataCalculator ? data).collect {
case Success(_) =>
Right(Created -> "")
case throwable: MyInternalValidatationException =>
Left(BadRequest -> s"""{"${throwable.subject}" : "${throwable.cause}"}""")
}
}})
}
}
and simple actor wchich always responds when receive object Data and has own receive block wrapped in LoggingReceive, so I should see logs when message is receiving by actor
and i test it using (I think simple code)
class SampleStarngeTest extends WordSpec with ThisAppTestBase with OneInstancePerTest
with routeTestingSugar {
val url = "/firstPath/"
implicit val routeTestTimeout = RouteTestTimeout(5 seconds)
def postTest(data: String) = Post(url).withJson(data) ~> routes
"posting" should {
"pass" when {
"data is valid and comes from the identified user" in {
postTest(correctData.copy(createdAt = System.currentTimeMillis()).asJson) ~> check {
print(entity)
status shouldBe Created
}
}
"report is valid and comes from the anonymous" in {
postTest(correctData.copy(createdAt = System.currentTimeMillis(), adid = "anonymous").asJson) ~> check {
status shouldBe Created
}
}
}
}
}
and behavior:
When I run either all tests in package (using Intellij Idea 14 Ultimate) or sbt test I encounter the same results
one execution -> all tests pass
and next one -> not all pass, this which not pass I can see:
1. fail becouse Request was neither completed nor rejected within X seconds ( X up tp 60)
2. system console output from route from line post(handleWith { (data: Data) =>{ println("receiving data"), so code in handleWith was executed
3. ask timeout exception from route code, but not always (among failed tests)
4. no logs from actor LoggingReceive, so actor hasn't chance to respond
5. when I rerun teststhe results are even different from the previous
Is there problem with threading? or test modules, thread blocking inside libraries? or sth else? I've no idea why it isn't work :(

How to mock domain specific closures in Spock

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