So I have the following bit of code
class MetricsLogger {
def measure[T](name:String)(operation: => T): T = {
val startTime = System.currentTimeMillis
val result = try {
operation
} finally {
logMetric(Metric(name, System.currentTimeMillis - startTime, StandardUnit.Milliseconds))
}
result
}
}
Where log Metric is some kind of side effect (e.g. upload metric to cloudwatch).
Now I am doing this like
def measuredOp = measure("metricName") { someOperation }
Here some operation is making some network calls.
Now I have to stub measured op.
So my stub is as the follows:-
val loggingMetrics = mock[MetricsLogger] // mock is from MockitoSugar trait
and my stubbing is like
Mockito.when(loggingMetrics.measure(Matchers.anyString())(Matchers.anyObject())).thenReturn(???)
So obviously my stubbing is wrong, but I cannot figure how to stub this properly.
Mockito doesn't support that as by-name parameters it's a concept that doesn't exists in Java, however, mockito-scala does support this from version 0.4.0 (try 0.4.0 or 0.4.2, ignore 0.4.1)
I just run a quick test like this
import org.mockito.{ MockitoSugar, ArgumentMatchersSugar }
class StackOverflowTest extends WordSpec with MockitoSugar with scalatest.Matchers with ArgumentMatchersSugar {
"mock[T]" should {
"it should work with by-name params" in {
val loggingMetrics = mock[MetricsLogger]
when(loggingMetrics.measure(any)(any)).thenReturn("it worked!")
loggingMetrics.measure("test")("") shouldBe "it worked!"
}
}
}
Disclaimer: I'm a maintainer of that library although it's part of the official Mockito suite
Related
I have the following code written in Scala, Guice, Mockito and ScalaTest
import javax.inject.Singleton
import com.google.inject.Inject
#Singleton
class TestPartialMock #Inject()(t1: Test1, t2: Test2) {
def test3() = "I do test3"
def workHorse() : List[String] = {
println("+++++ came inside ++++++++")
List(t1.test1(), t2.test2(), test3())
}
}
class MainModule extends ScalaModule {
override def configure() = {
bind[Test1]
bind[Test2]
bind[TestPartialMock]
}
}
and I have written unit test cases with partial mocking
class PartialMockTest extends FunSpec with Matchers {
describe("we are testing workhorse but mock test3") {
it("should return mock for test3") {
val module = new TestModule
val injector = Guice.createInjector(module)
val tpm = injector.getInstance(classOf[TestPartialMock])
val result = tpm.workHorse()
result should contain ("i do test2")
result should contain ("i do test1")
result should contain ("I am mocked")
result should not contain ("I do test3")
}
}
}
class TestModule extends AbstractModule with ScalaModule with MockitoSugar {
override def configure() = {
val module = new MainModule()
val injector = Guice.createInjector(module)
val realobject = injector.getInstance(classOf[TestPartialMock])
val x = spy(realobject)
when(x.test3()).thenReturn("I am mocked")
when(x.workHorse()).thenCallRealMethod()
bind(classOf[TestPartialMock]).toInstance(x)
}
}
My tests are successful and I can see that it mocks the right set of methods and calls the actual implementation of the right set of methods. BUT when I look at the output I see
info] Compiling 5 Scala sources to /Users/IdeaProjects/GuicePartialMock/target/scala-2.12/classes...
[info] Compiling 1 Scala source to /Users/IdeaProjects/GuicePartialMock/target/scala-2.12/test-classes...
+++++ came inside ++++++++
+++++ came inside ++++++++
[info] PartialMockTest:
[info] we are testing workhorse but mock test3
[info] - should return mock for test3
[info] Run completed in 2 seconds, 92 milliseconds.
Why am I seeing the print statement came inside twice?
Edit::
Based on advice of Tavian ... this is the final code which worked
class TestModule extends AbstractModule with ScalaModule with MockitoSugar {
override def configure() = {
val module = new MainModule()
val injector = Guice.createInjector(module)
val realobject = injector.getInstance(classOf[TestPartialMock])
val x = spy(realobject)
when(x.test3()).thenReturn("I am mocked")
bind(classOf[TestPartialMock]).toInstance(x)
}
}
For spies, you need to be careful of expressions like
when(x.workHorse()).thenCallRealMethod()
because x.workHorse() really is invoked in this expression! x doesn't "know" that it's inside a when() call, as the expression is lowered into something like this:
tmp1 = x.workHorse();
tmp2 = when(tmp1);
tmp3 = tmp2.thenCallRealMethod();
Instead, you can write
doCallRealMethod().when(x).workHorse()
which will suppress the invocation of the real workHorse() implementation.
But, you don't need to do any of this for this example—calling real methods is the default behaviour of spies.
As you mentioned in the question title, you have a combination of 3 technologies. Actually 4 technologies including build tool that is used to run the test. You can isolate the problem by
1) Remove Guice and instantiate everything directly
2) Run code as a simple App instead of running as a test by sbt/gradle/maven.
Also it makes sense to print stack trace together with a came inside message to find a caller.
If I don't actually have an explicit assertions like count must_== 1 a in Specs2 test, I'd get an error indicating no implicit could be found.
// doesn't compile
class Example extends Specification {
"You need an assertion" >> {
// hello!
}
}
Fair enough.
But if I also use scalamock's MockContext, I can rely on just expectations rather than assertions; mock something and scalamock will verify methods are called etc;
class MockExample extends Specification {
"I can use 'expectations' here instead" in new MockContext {
val foo = mock[Foo]
(foo.bar _).expects(*).once
// no explicit assertions
}
}
However, if I try and share context setup by mixing in IsolatedMockFactory, I'm back to the compiler failure. Any ideas how to fix it?
// doesn't compile
class AnotherMockExample extends Specification with IsolatedMockFactory {
val foo = mock[Foo]
"I can't use 'expectations' here any more" >> {
(foo.bar _).expects(*).once
}
}
An example in specs2 accepts anything that has an org.specs2.execute.AsResult typeclass instance. Since (foo.bar _).expects.once is of type CallHandler you can create an AsResult instance for CallHandler that just evaluates the value and returns Success
implicit def CallHandlerAsResult[R : Defaultable]: AsResult[CallHandler[R]] = new AsResult {
def asResult(c: =>CallHandler[R]) = {
c
Success
}
}
Since failures are exception-based in ScalaMock this should result in an exception being thrown if some mock expectation is not satisfied.
In our project we use Scala Specs2 together with Selenium.
I'm trying to implement screenshot-on-failure mechanism "in a classic way (link)" for my tests, using JUnit annotations, but, the rule doesn't called on test failure at all.
The structure of the test is as follows:
class Tests extends SpecificationWithJUnit{
trait Context extends LotsOfStuff {
#Rule
val screenshotOnFailRule = new ScreenshotOnFailRule(driver)
}
"test to verify stuff that will fail" should {
"this test FAILS" in new Context {
...
}
}
The ScreenshotOnFailRule looks like this:
class ScreenshotOnFailRule (webDriver: WebDriver) extends TestWatcher {
override def failed(er:Throwable, des:Description) {
val scrFile = webDriver.asInstanceOf[TakesScreenshot].getScreenshotAs(OutputType.FILE)
FileUtils.copyFile(scrFile, new File(s"/tmp/automation_screenshot${Platform.currentTime}.png"))
}
}
I understand that probably it doesn't work now because the tests aren't annotated with #Test annotation.
Is it possible to annotate the Specs2 tests with JUnit #Rule annotation?
According to this question it seems as if JUnit Rules aren't supported. But you could try to make use of the AroundExample trait:
import org.specs2.execute.{AsResult, Result}
import org.specs2.mutable._
import org.specs2.specification.AroundExample
class ExampleSpec extends Specification with AroundExample {
// execute tests in sequential order
sequential
"The 'Hello world' string" should {
"contain 11 characters" in {
"Hello world" must have size (10)
}
// more tests..
}
override protected def around[T](t: => T)(implicit ev: AsResult[T]): Result = {
try {
AsResult.effectively(t)
} catch {
case e: Throwable => {
// take screenshot here
throw e
}
}
}
}
I am using Specs2 with play 2.2.1 built with Scala 2.10.2 (running Java 1.7.0_51). I have been reading about how to do setup/teardown with Specs2. I have seen examples using the "After" trait as follows:
class Specs2Play extends org.specs2.mutable.Specification {
"this is the first example" in new SetupAndTeardownPasswordAccount {
println("testing")
}
}
trait SetupAndTeardownPasswordAccount extends org.specs2.mutable.After {
println("setup")
def after = println("teardown ")
}
This works fine, except that all of my tests are using "in new WithApplication". It seems what I need is to have an object which is both a "WithApplication" and an "After". Below does not compile, but is essentially what I want:
trait SetupAndTeardownPasswordAccount extends org.specs2.mutable.After with WithApplication
So, my question is, how do I add setup/teardown to my tests which are already using "in WithApplication"? My primary concern is that all of our tests make use of fake routing like this (so they need the With Application).
val aFakeRequest = FakeRequest(method, url).withHeaders(headers).withBody(jsonBody)
val Some(result) = play.api.test.Helpers.route(aFakeRequest)
result
This is the code for WithApplication:
abstract class WithApplication(val app: FakeApplication = FakeApplication()) extends Around with Scope {
implicit def implicitApp = app
override def around[T: AsResult](t: => T): Result = {
Helpers.running(app)(AsResult.effectively(t))
}
}
It's actually quite easy to modify this to suit your needs without creating a bunch of other traits. The missing piece here is the anonymous function t, which you provide the implementation for in your tests (using WithApplication). It would be nice to make WithApplication a little more robust to be able to execute arbitrary blocks of code before and after the tests, if necessary.
One approach could be to create a similar class to WithApplication that accepts two anonymous functions setup and teardown that both return Unit. All I really need to do is modify what's happening inside AsResult.effectively(t). To keep this simple, I'm going to remove the app parameter from the parameter list, and use FakeApplication always. You don't seem to be providing a different configuration, and it can always be added back.
abstract class WithEnv(setup: => Unit, teardown: => Unit) extends Around with Scope {
implicit def implicitApp = app
override def around[T: AsResult](t: => T): Result = {
Helpers.running(app)(AsResult.effectively{
setup
try {
t
} finally {
teardown
}
})
}
}
Instead of simply calling the anonymous function t, I first call setup, then t, then teardown. The try/finally block is important because failed tests in specs2 throw exceptions, and we want to be sure that teardown will be executed no matter what the outcome.
Now you can easily setup test environments using functions.
import java.nio.files.{Files, Paths}
def createFolder: Unit = Files.createDirectories(Paths.get("temp/test"))
def deleteFolder: Unit = Files.delete("temp/test")
"check if a file exists" in new WithEnv(createFolder, deleteFolder) {
Files.exists(Paths.get("temp/test")) must beTrue
}
(This might not compile, but you get the idea.)
If your after method doesn't need anything from the WithApplication trait you can mix in your specification the AfterExample trait and define the after behaviour for the whole spec:
import org.specs2.specification._
class Specs2Play extends org.specs2.mutable.Specification with AfterExample {
"this is the first example" in new SetupAndTeardownPasswordAccount {
pending("testing")
}
trait SetupAndTeardownPasswordAccount extends WithApplication
def after = println("cleanup")
}
I'm using Scala 2.10, specs2 and Mockito. I want to mock scala.io.Source.fromURL(). The issue seems to be fromURL() is a function in io.Source's object.
val m = mock[io.Source]
m.fromURL returns io.Source.fromString("Some random string.")
It's a pretty straightforward mock in an Unit test. Why isn't it working?
Thanks!
Instead of mocking it, you could try spying it as follows:
val m = spy(io.Source)
Or you could mock it as follows:
val m = mock[io.Source.type]
But then how are you using Source in the class you are testing? If you had an example class like so:
class MyClass{
def foo = {
io.Source.doSomething //I know doSomething is not on Source, call not important
}
}
Then in order to take advantage of mocking/spying, you'd have to structure your class like so:
class MyClass{
val source = io.Source
def foo = {
source.doSomething
}
}
And then your test would have to look something like this:
val mockSource = mock[io.Source.type]
val toTest = new MyClass{
override val source = mockSource
}
In the Java world, static methods are the bane of mocking. In the Scala world, calls to objects can also be troublesome to deal with for unit tests. But if you follow the code above, you should be able to properly mock out an object based dependency in your class.
Good news! With the latest 1.16 release of mockito-scala, you can now mock scala objects.
To enable withObjectMocked feature, it is mandatory to create the file src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker containing a single line:
mock-maker-inline
Example:
object FooObject {
def simpleMethod: String = "not mocked!"
}
"mock" should {
"stub an object method" in {
FooObject.simpleMethod shouldBe "not mocked!"
withObjectMocked[FooObject.type] {
FooObject.simpleMethod returns "mocked!"
//or
when(FooObject.simpleMethod) thenReturn "mocked!"
FooObject.simpleMethod shouldBe "mocked!"
}
FooObject.simpleMethod shouldBe "not mocked!"
}
}
See: https://github.com/mockito/mockito-scala#mocking-scala-object
Years later, above answer doesn't work as others have pointed out.
And you cannot mock the scala.io.Source object.
Can I mock final / private methods or classes? This is not supported, as mocks generated with macros are implemented as subclasses of the type to mock. So private and final methods cannot be overridden. You may want to try using an adapter or façade in your code to make it testable. It is better to test against a trait/interface instead of a concrete implementation. There are libraries that support this kind of mocking, such as PowerMock. Be aware that this kind of mocking involves Bytecode manipulation, which has the risk that your test double diverges from the actual implementation.
So what I did is an work around to abstract out scala.io.Source.fromUrl() as a function argument and pass in mocked function in tests.
// original func
def aFuncThatUsesSource() = {
val source = scala.io.Source("127.0.0.1:8080/...")
val result = source.mkString
Try(source.close())
result
}
// test friendly func that accepts `scala.io.Source.fromURL` as arg
def aTestFriendlyFunc(makeApiCall: String => BufferedSource) = {
val source = makeApiCall("127.0.0.1:8080/...")
val result = source.mkString
Try(source.close())
result
}
....
// test spec
def testyMcTesterson = () => {
val makeApiCall = mockFunction[String, BufferedSource]
makeApiCall.expects("something...")
.returns( new BufferedSource(new ByteArrayInputStream("returns something".getBytes)) )
aTestFriendlyFunc(makeApiCall) shouldEqual "returns something"
}