-
Notifications
You must be signed in to change notification settings - Fork 100
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
An unexpected call to one of the method of a mock doesn't always fails a test #223
Comments
why would this test fail if you wrap the call in a try/catch? |
I would expect the test to fail if any of the "Expectations" are not met. If I set the expectation that the method is called twice (with In this minimal example, it's easy to just remove the try/catch. But in my real use-case the mock is used in a place where I need to handle any arbitrary exception. To add to that, the call is inside a Future, inside an Akka actor, so I cannot just let the exception be raised. My expectation is that when the expectation are checked at the end of a test, the mock is also tested for unexpected calls. |
you do have the choice between |
I vote for this. For example, when the test assumes 2 calls of a function but there are actually 3 calls, it silently passes while when there would be only one, it would fail. |
@KarelCemus please provide a concrete example where you think an issue exists. I pointed out the relevant documentation above regarding mock / stub behaviour and you already have a choice of "expectations first" or "record then verify". |
Wow, I'm having the exact same issue being reported above. I'm mocking a call that returns a Future. I want to test the behavior which is Future.failed(some exception....). Farther up the stack we do a recover on that exception type so we can turn it into a reasonable error message from a REST call (using play framework). So the exception that is getting thrown by scalamock invokes that block, and the test silently passes if there is some unexpected mock invocation... I also would vote for the "record unexpected call" and then verify behavior. |
I have a very similar scenario - use a mock within an Akka actor responsible for network communication and it is supposed to recover from all exception, which unfortunately includes the exception thrown by the mock itself, which leads me to the need of manual verification of both expected and unexpected calls at the end of a test. However, I'd like to point to the inconsistency. While the expectations are evaluated at the end of a test, unexpected calls are reported directly during a test. I am aware of the issue that late reporting of unexpected calls may hide an original cause of a test failure and the test may fail due to a different reason but still, there should exist an option to manually report unexpected calls, therefore report them twice or switch a mechanism. If I get it right, a mock is an object with simulated behavior and we are interested in monitoring all interactions with such an object, which includes unexpected call, while a stub does not have to be monitored at all. Therefore, swapping them does not seem semantically correct. Implementation of the verification of unexpected calls is actually pretty simple, it is like 4 lines of code. I already did it myself, although I had to copy-paste a lot of ScalaMock's code as it is pretty closed (lots of trait MockFactoryRecordingUnexpectedCalls extends MockFactoryBase {
private var unexpectedCalls = new CallLog
override private[scalamock] def reportUnexpectedCall(call: Call): Nothing = {
unexpectedCalls += call
super.reportUnexpectedCall(call)
}
override protected def withExpectations[T](what: => T): T = {
if (expectationContext == null) {
// we don't reset expectations for the first test case to allow
// defining expectations in Suite scope and writing tests in OneInstancePerTest/isolated style
initializeExpectations()
}
try {
val result = what
reportUnexpectedCalls()
verifyExpectations()
result
} finally {
clearExpectations()
}
}
private def initializeExpectations() {
val initialHandlers = new UnorderedHandlers
callLog = new CallLog
unexpectedCalls = new CallLog
expectationContext = initialHandlers
currentExpectationContext = initialHandlers
}
private def clearExpectations(): Unit = {
// to forbid setting expectations after verification is done
callLog = null
expectationContext = null
currentExpectationContext = null
}
private def verifyExpectations() {
callLog foreach expectationContext.verify _
if (!expectationContext.isSatisfied)
reportUnsatisfiedExpectation(callLog, expectationContext)
}
private def reportUnexpectedCalls(): Unit = {
var calls: List[String] = Nil
unexpectedCalls.foreach {
call => calls = s"Unexpected call: $call" :: calls
}
if (calls.nonEmpty) throw newExpectationException(calls.reverse.mkString("", "\n", s"\n\n${errorContext(callLog, expectationContext)}"))
}
} This workaround is pretty ugly but most of the code already exists in the |
If it's useful to people then we could add the Don't get too hung up on mock vs stub terminology please. In Scalamock, the difference is that one is fail early while the other is fail late (or not fail at all, i you don't verify calls). |
An unexpected call to one of the method of a mock raise an
org.scalatest.exceptions.TestFailedException
. But if this exception is somehow suppressed, the failure is silently ignored.ScalaMock Version (e.g. 3.5.0)
4.1.0
Scala Version (e.g. 2.12)
2.12.4
Runtime (JVM or JS)
JVM
Please describe the expected behavior of the issue
The test should fail with an "Unexpected call: ..." error.
Please provide a description of what actually happens
The test doesn't fails.
Reproducible Test Case
The text was updated successfully, but these errors were encountered: