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))
}
Related
I am learning how to write unit tests with Groovy. I'm familiar with both EasyMock and Mockito but thought I'd try the pure Groovy way. The class I want to test has multiple collaborators I need to mock. The examples for MockFor demonstrate mock.use, but don't indicate how to employ more than one mock. So, I extended the Family/Person example to include a Pet and wrote a sample test for a method needing both a Person and a Pet. The only way I found to apply both a Person mock and a Pet mock was to nest mock.use closures as shown below.
This works (produces a JUnit green bar), but I'm wondering if it's the right/best way to do it? It could get ugly fast if I have to mock several collaborators in this fashion - nesting N levels deep. Ugh.
import groovy.mock.interceptor.MockFor
import org.junit.Test
class FamilyTest {
#Test
void testCuddle() {
def kidMock = new MockFor(Person)
kidMock.demand.getFirst {'Kid'}
kidMock.use {
def catMock = new MockFor(Pet)
catMock.demand.getName {'Cat'}
catMock.use {
def family = new Family(kid:new Person(), cat:new Pet())
assert family.cuddle() == 'Kid hugs Cat'
}
catMock.expect.verify()
}
kidMock.expect.verify()
}
class Person {
String first, last
}
class Pet {
String name
}
class Family {
Person kid
Pet cat
// method under test
def cuddle() { "$kid.first hugs $cat.name" }
}
}
Edit: The below works, but the verify methods don't match the documentation, which say to use mock.expect.verify(). When I try the latter, I get an exception "expected 1 call, got 0".
Again I wonder - it works, but is it the right/preferred/best way?
#Test
void testCuddle2() {
def kidMock = new MockFor(Person)
kidMock.demand.with {getFirst {'Kid'}}
def catMock = new MockFor(Pet)
catMock.demand.with {getName {'Cat'}}
def kidProxy = kidMock.proxyInstance();
def catProxy = catMock.proxyInstance();
def family = new Family(kid:kidProxy, cat:catProxy)
assert family.cuddle() == 'Kid hugs Cat'
kidMock.verify(kidProxy)
catMock.verify(catProxy)
}
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.
Let's say that I have a mocked trait Foo:
trait Foo {
def op(x: String): Unit
}
and I mocked this interface using
val mockedFoo = mock[Foo]
I want the method op to throw an exception second time I call it, e.g.
import org.specs2.mock.Mockito
import org.specs2.mutable.Specification
trait Foo {
def op(x: String): Unit
}
class DummySpec extends Specification with Mockito {
"dummy" should {
"test" in {
val mockedFoo = mock[Foo]
org.mockito.Mockito.doNothing().doThrow(new RuntimeException).when(mockedFoo).op(any[String])
mockedFoo.op("This one should work fine") should not(throwAn[Exception])
mockedFoo.op("This one should throw an exception") should throwAn[Exception]
}
}
}
Is there a way to do this in specs2 style? e.g.
mockedFoo.op(any[String]) returns Unit thenThrows new RuntimeException
but this doesn't compile.
Thanks!
The Unit return type makes things a bit trickier as you can't just chain:
returns "foo" thenThrows new RuntimeException
But you can still solve this problem if you use answers like below:
mockedFoo.op(anyString) answers {args => } thenThrows new RuntimeException
See if this works for you.
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'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
}