I'm currently trying to run the same test cases for 2 different classes but having issues with the setup(), I see similar questions, but haven't seen the solution for groovy testing with Spock, and I haven't been able to figure it out.
So I am essentially solving the same problem using 2 different methods, so the same test cases should be applicable to both classes, I am trying to stay Don't Repeat Yourself (DRY).
So I've set up a MainTest as an abstract class and the MethodOneTest and MethodTwoTest as concrete classes that extend the abstract MainTest:
import spock.lang.Specification
abstract class MainTest extends Specification {
private def controller
def setup() {
// controller = i_dont_know..
}
def "test canary"() {
expect:
true
}
// more tests
}
My concrete classes are something like this:
class MethodOneTest extends MainTest {
def setup() {
def controller = new MethodOneTest()
}
}
class MethodTwoTest extends MainTest {
def setup() {
def controller = new MethoTwoTest()
}
}
So does anyone know how I can do run all the tests in abstract MainTest from my concrete classes MethodOneTest and MethodTwoTest? How to instantiate the setup properly? I hope I am being clear.
Just forget about controller setup. All tests from superclass will be automatically executed when you execute tests for concrete class. E.g.
import spock.lang.Specification
abstract class MainTest extends Specification {
def "test canary"() {
expect:
true
}
// more tests
}
class MethodOneTest extends MainTest {
// more tests
}
class MethodTwoTest extends MainTest {
// more tests
}
But it should have sence to run the same tests more than once. So it is resonable to parameterize them with something, e.g. some class instance:
import spock.lang.Specification
abstract class MainSpecification extends Specification {
#Shared
protected Controller controller
def "test canary"() {
expect:
// do something with controller
}
// more tests
}
class MethodOneSpec extends MainSpecification {
def setupSpec() {
controller = //... first instance
}
// more tests
}
class MethodTwoSpec extends MainSpecification {
def setupSpec() {
controller = //... second instance
}
// more tests
}
Related
So we have a restful service that we want to test using a restclient in grails.
The test code should go something like this...
class MyControllerSpec extends Specification {
def setup() {
this.dbEntity = new DbEntity("someid123").save();
}
void "Test entity GET"{
given:
RestBuilder rest = new RestBuilder()
when: "The DB entity service is hit"
RestResponse restResponse = rest.post("http://localhost:8080/api/someentity/$id");
then: "A 200 error is sent"
restResponse.status == 200
}
The problem I am having is the setup method blows up on .save() because there is not hibernate session. How can I manipulate my database before running a test?
You can define a method named like "setupData", and call it in the "given" block of "Test entity GET" testcase.
def setupData() { this.dbEntity = new DbEntity("someid123").save(); }
If you need to load some data before each funcional test, you can create a helper class, with #Shared variables or methods or both. Even you could override the setup, setupSpec methods in that class.
Your first class does not extends Specification now, DataLoader class (helper class) instead.
class MyControllerSpec extends DataLoader {
void setup(){
createEntity()
}
void "Test entity GET"{
given:
RestBuilder rest = new RestBuilder()
when: "The DB entity service is hit"
RestResponse restResponse = rest.post("http://localhost:8080/api/someentity/$dbEntity.id");
then: "A 200 error is sent"
restResponse.status == 200
}
}
And your helper class is the one which extends Specification, with its methods and #Shared variables.
import spock.lang.Shared
class DataLoader extends Specification {
#Shared DbEntity dbEntity
void createEntity(){
dbEntity = new DbEntity("someid123").save();
}
}
When extending GebSpec in Grails 2.5.6, none of the other answers helped: I would still get
Method on class [...] was used outside of a Grails application
on the save() call.
Adding #TestFor(DbEntity) to the test class helped.
NB: While that annotation breaks integration tests, it seems to be necessary here. Not sure why that is.
You probably want to use the remote-control plugin. In Grails 2.x, add this to your BuildConfig.groovy:
repositories {
...
mavenRepo "http://dl.bintray.com/alkemist/maven/"
}
plugins {
...
test ":remote-control:2.0"
}
After refreshing dependencies and potentially adjusting some settings (see e.g. here and here), you can use it like so in tests:
// <project>/test/functional/<package>/MyControllerSpec.groovy
class MyControllerSpec extends GebSpec {
RemoteControl remote
DbEntity dbEntity
def setup() {
this.remote = new RemoteControl()
this.dbEntity = remote {
new DbEntity("someid123").save()
}
}
def cleanup() {
remote {
DbEntity.findAll().each { dbe ->
println("Deleting $dbe")
dbe.delete()
}
}
}
Note:
You can invoke remote in given/setup and when blocks as well.
Sometimes, it seems to be necessary to wrap core in remote { ... } in a DbEntity.withTransaction { ... }. Maybe that's obvious for the more intitiated; I stumbled over that.
If you want to return a DbEntity from remote it must be serializable.
I have a Groovy/Spock unit test as follows:
public class ThingUnitTest extends Specification {
def "doing a thing delegates to the context"() {
given : def thing = createThing()
when : thing.doThing()
then : 1 * thing.context.doThing()
}
def createThing() {
def thing = new ThingImpl()
thing.context = createThingContext()
return thing
}
def createThingContext() {
def context = Spy(ThingContext)
context.foo = Mock(Foo)
context.bar = Mock(Bar)
return context
}
}
This test will run without problems. However it turns out that I have other tests that need a ThingContext, so I want to move the createThingContext code into a common class:
public class ThingContextFactory extends Specification {
def createThingContext() {
def context = Spy(ThingContext)
context.foo = Mock(Foo)
context.bar = Mock(Bar)
return context
}
}
and then write my unit tests as follows:
public class ThingUnitTest extends Specification {
...
def createThingContext() {
return new ThingContextFactory().createThingContext()
}
}
But now the test fails, with the assertion 1 * thing.context.doThing() failing with zero interactions.
I also tried the following:
public class ThingContextFactory {
def createThingContext() {
def mocking = new MockingApi()
def context = mocking.Spy(ThingContext)
context.foo = mocking.Mock(Foo)
context.bar = mocking.Mock(Bar)
return context
}
But now the tests fail with MockingApi.invalidMockCreation ... InvalidSpec
Note that I do not want to use inheritance here, but move common mocking code into helper classes. But when I do this my spock tests fail.
Is there some proper way to refactor Spock mocking code?
As of Spock 0.7, mock objects can only be created in the test class that uses them, or a superclass thereof. This might change in the next version.
I have a little problem here and really have no idea how to implement unit testing for logger messages. Of course, it sounds a little weird, but for me it's really interesting topic. But let me be more specific.
I have some scala class and test specification:
class Testable extends Logging {
def method() = {
// some method calls
logger.info("Message1")
}
}
class TestableSpec extends Specification with ShouldMatchers with Mockito {
"Testable instance" should {
// some important tests
"print proper log message during method call" in {
// And how to test that logger really prints proper message ("Message1")?
}
}
}
My first thought was to intercept underlying logger engine messages but it seems a little hard thing to implement due to usage of mixins in Testable class, therefore any ideas to do such things would be very helpful.
UPDATE:
I finally implemented a test and decided to share my solution with community. We cannot mock scalalogging.Logger class directly because it's final but we still can mock underlying slf4j Logger. To clarify an idea:
class Testable extends Logging {
def foo() = {
// ...
logger.info("Foo has been called")
}
}
// Another imports are omitted.
import com.typesafe.scalalogging.slf4j.Logger
import org.slf4j.{Logger => Underlying}
class TestableSpec extends Specification with Mockito with ShouldMatchers {
def initTestable(mocked: Underlying): Testable = {
new Testable() {
override lazy val logger = Logger(mocked)
}
}
"Testable instance" should {
"invoke logger with a proper message" in {
val mocked = mock[Underlying]
mocked.isInfoEnabled returns true // Should be set to true for test
initTestable(mocked).foo()
there was one(mocked).info("Foo has been called")
}
}
}
Thanks Eric for his help. His answer was a key to the solution.
One possibility is to use Mockito to check method calls:
class Testable extends Logging {
def method() = {
// some method calls
logger.info("Message1")
}
}
class TestableSpec extends Specification with ShouldMatchers with Mockito {
"Testable instance" should {
"print proper log message during method call" in {
val mockLogger = mock[Logger]
val testable = new Testable {
// switch the logger with a mock instance
override val logger = mockLogger
}
testable.method()
there was one(mockLogger).info("Message1")
}
}
}
This is the main idea but you might have to adapt it depending on your exact traits and logging framework:
logger must be overridable
the info method must not be final (one of Mockito's limitations)
Good question... and good answer ! I had some trouble with the Mockito mixin. So I am using Eric's approach with the Java DSL for Mockito. If anyone is interested in this variation, here is the slightly modified code:
import com.typesafe.scalalogging.{LazyLogging, Logger, StrictLogging}
import org.mockito.Mockito
import org.mockito.Mockito._
import org.slf4j.{Logger => Underlying}
class Testable extends LazyLogging {
def foo() = {
logger.info("Foo has been called")
}
}
import org.junit.runner.RunWith
import org.scalatest.{BeforeAndAfterEach, FunSuite}
import org.scalatest.junit.JUnitRunner
import org.scalatest.matchers.ShouldMatchers
#RunWith(classOf[JUnitRunner])
class LoggerTest
extends FunSuite with ShouldMatchers with BeforeAndAfterEach {
def initTestable(mocked: Underlying): Testable = {
new Testable() {
override lazy val logger = Logger(mocked)
}
}
test("the mockito stuff") {
val mocked = Mockito.mock(classOf[Underlying])
when(mocked.isInfoEnabled()).thenReturn(true)
initTestable(mocked).foo()
verify(mocked).info("Foo has been called")
}
}
I am trying to write a unit test for a java class that is extending an abstract class? The java class looks sort of like:
public class XYZFilter extends XYZDataFilter{
#Override
protected boolean filterItem(Model d, String sector) {
//method code
return true;
}
}
The junit test class looks like:
import org.junit.Test;
import static org.junit.Assert.assertTrue;
public class XYZFilterTest {
Model m = new Model();
String sector = "SECTOR";
#Test
public void testFilterItem() throws Exception {
System.out.println("\nTest filterItem method...");
XYZFilter f = new XYZFilter();
assertTrue(f.filterItem(m, sector));
}
}
So I'm having a problem with the abstract DataFilter which is extended by the Filter class, as well as the Model class. I believe I need to mock these objects using JMockit but I am having a lot of trouble figuring out how to do this. Any advice is appreciated.
The answer is I needed to have the libraries included, JMockit doesn't handle objects in that way.
I had a simple class that naturally divided into two parts, so I refactored as
class Refactored extends PartOne with PartTwo
Then the unit tests started failing.
Below is an attempt to recreate the problem. The functionality of all three examples is the same, but the third test fails with a NullPointerException as indicated. What it is about the use of traits that is causing the problem with mockito?
Edit: Is Mockito the best choice for Scala? Am I using the wrong tools?
import org.scalatest.junit.JUnitSuite
import org.scalatest.mock.MockitoSugar
import org.mockito.Mockito.when
import org.junit.Test
import org.junit.Before
class A(val b:B)
class B(val c:Int)
class First(){
def getSomething(a:A) = a.b.c
}
class Second_A extends Second_B
class Second_B{
def getSomething(a:A) = a.b.c
}
class Third_A extends Third_B
trait Third_B{
// Will get a NullPointerException here
// since a.b will be null
def getSomething(a:A) = a.b.c
}
class Mocking extends JUnitSuite with MockitoSugar{
var mockA:A = _
#Before def setup { mockA = mock[A] }
#Test def first_PASSES {
val mockFirst = mock[First]
when(mockFirst.getSomething(mockA)).thenReturn(3)
assert(3 === mockFirst.getSomething(mockA))
}
#Test def second_PASSES {
val mockSecond = mock[Second_A]
when(mockSecond.getSomething(mockA)).thenReturn(3)
assert(3 === mockSecond.getSomething(mockA))
}
#Test def third_FAILS {
val mockThird = mock[Third_A]
//NullPointerException inside here (see above in Third_B)
when(mockThird.getSomething(mockA)).thenReturn(3)
assert(3 === mockThird.getSomething(mockA))
}
}
Seems Mockito has some kind of problem seeing the relationship between class and trait. Guess this is not that strange since traits are not native in Java. It works if you mock the trait itself directly, but this is maybe not what you want to do? With several different traits you would need one mock for each:
#Test def third_PASSES {
val mockThird = mock[Third_B]
when(mockThird.getSomething(mockA)).thenReturn(3)
assert(3 === mockThird.getSomething(mockA))
}