ScalaTest hides setup failures in FreeSpec - scala

when I run the following test it throws an exception directly in the description clause, befor e it reaches the in clause:
"when the message send actor receives a reference to an address" - {
val unusedInThisTestActor = mock[ActorRef]
val serviceFacade = testActor
val keys = Array("password")
val values = Array("cheese")
val addressRef = TestActorRef[ServiceEndpoint]
val messageSender = system.actorOf(new Props(() => new MessageSendActor(unusedInThisTestActor, serviceFacade, unusedInThisTestActor)))
messageSender ! ReferenceToAddress(addressRef, ("command", keys, values))
"it tells the service facade to send the command to the address reference" in {
expectMsg(SendCommandToService(addressRef,("command", keys, values)))
}
}
ScalaTest then ignores this test, rather than saying it failed which leaves everyone thinking the code is working fine. The only way to notice something went wrong is to look carefully at the output:
[ERROR] [06/16/2013 10:31:05.722] [main] [akka://testactorsystems/user/$$a] error while processing Create(622541251)
d7565b2b-b0a4-4af6-83c7-ed67f7bf0302akka.actor.ActorInitializationException: exception during creation
at akka.actor.ActorInitializationException$.apply(Actor.scala:170)
And use this to work out which tests aren't being run.
This is not very helpful, and I would prefer scala test to mark this as a failure somehow. Is that possible?

Related

scala - scalatest - eventually trait wins over fail assertion?

by documentation,
eventually trait
Invokes the passed by-name parameter repeatedly until it either
succeeds, or a configured maximum amount of time has passed, sleeping
a configured interval between attempts.
but fail,
fail to fail a test unconditionally;
so i want to use eventually in order to wait until a successful status arrived, but use fail to fail the test if i already know that the test must to fail
e.g.
converting a video with ffmpeg i will wait until conversion is not completed but if conversion reach "error" status i want to make the test fail
with this test
test("eventually fail") {
eventually (timeout(Span(30, Seconds)), interval(Span(15, Seconds))) {
println("Waiting... ")
assert(1==1)
fail("anyway you must fail")
}
}
i understand that i cannot make a test "fail unconditionally" inside eventually cicle : it looks like eventually will ignore "fail" until timeout.
is this a correct behaviour?
so, in the assertion scalatest documentation, fail should not "fail test unconditionally" but it "throw exception"?
It's the same because the only way to fail a test in Scalatest is to throw an exception.
Look at the source:
def eventually[T](fun: => T)(implicit config: PatienceConfig): T = {
val startNanos = System.nanoTime
def makeAValiantAttempt(): Either[Throwable, T] = {
try {
Right(fun)
}
catch {
case tpe: TestPendingException => throw tpe
case e: Throwable if !anExceptionThatShouldCauseAnAbort(e) => Left(e)
}
}
...
So if you want to get your failure through, you could use pending instead of fail (but of course, the test will be reported as pending, not failed). Or write your own version of eventually which lets more exceptions through.

How can I get a return value from ScalaTest indicating test suite failure?

I'm running a ScalaTest (FlatSpec) suite programmatically, like so:
new MyAwesomeSpec().execute()
Is there some way I can figure out if all tests passed? Suite#execute() returns Unit here, so does not help. Ideally, I'd like to run the whole suite and then get a return value indicating whether any tests failed; an alternative would be to fail/return immediately on any failed test.
I can probably achieve this by writing a new FlatSpec subclass that overrides the Scalatest Suite#execute() method to return a value, but is there a better way to do what I want here?
org.scalatest.Suite also has run function, which returns the status of a single executed test.
With a few tweaking, we can access the execution results of each test. To run a test, we need to provide a Reporter instance. An ad-hoc empty reporter will be enough in our simple case:
val reporter = new Reporter() {
override def apply(e: Event) = {}
}
So, let's execute them:
import org.scalatest.events.Event
import org.scalatest.{Args, Reporter}
val testSuite = new MyAwesomeSpec()
val testNames = testSuite.testNames
testNames.foreach(test => {
val result = testSuite.run(Some(test), Args(reporter))
val status = if (result.succeeds()) "OK" else "FAILURE!"
println(s"Test: '$test'\n\tStatus=$status")
})
This will produce output similar to following:
Test: 'This test should pass'
Status=OK
Test: 'Another test should fail'
Status=FAILURE!
Having access to each test case name and its respective execution result, you should have enough data to achieve your goal.

Akka-Http: How to TestProbe a request

I have a request whose response depends on an actor reply. I am trying to test it in this way:
val myActor:TestProbe = TestProbe()
val route = new MyRoute() {
override def myServiceActor:ActorRef = {
myActor.ref
}
}.route
"return a query result for GET" in {
Get("/foo") ~> route ~> check {
myActor.expectMsg(ExecuteFoo())
myActor.reply(FOO)
responseEntity shouldEqual toJsonEntity(RequestResult(FOO))
}
}
I get correctly that expectMsg is verified but the reply is asynchronous respect to the responseEntity check. In this case the test fails.
Is there a way to wait for the reply?
You're on the right track using a TestProbe. The key is to separate the combination of running the request and then checking it (which you are doing as 1 step via check) into two explicit steps. First run it, then do any stubbing on the TestProbe and lastly, make your checks. The updated code for your sample would look like this:
val result = Get("/foo") ~> route ~> runRoute
myActor.expectMsg(ExecuteFoo())
myActor.reply(FOO)
check {
responseEntity shouldEqual toJsonEntity(RequestResult(FOO))
}(result)
You can see there that I'm first using runRoute to simple run the route without performing any checks. I assign this value to result as I will need this later to perform any checks. Then, you can safely do your stubbing against the TestProbe. At this point, it's already received the message and is waiting for your calls to verify what message it got and how to respond. Then, when done with that, we can call check, passing an explicit result (the one from runRoute) to that call instead of relying on an implicit.
If you follow this approach, you should be able to properly test routes that call an actor, using a TestProbe to do so.
One way of doing this (which might not be the right one or the only one) is using AutoPilot. Here is an example:
val myProbe = TestProbe()
myProbe.setAutoPilot(new TestActor.AutoPilot {
def run(sender: ActorRef, msg: Any) = msg match {
case ExecuteFoo(_) =>
//do something else if needed
sender ! FOO
TestActor.NoAutoPilot
}
})

Mocking Play WSRequestHolder get method using Scalamock

I'm trying to test the following line of code using ScalaTest and ScalaMock.
val responseFuture = wsClient.url(url).withQueryString(params: _*).get()
wsClient type is THttpClient, which is a wrapper of play.api.libs.ws.WS.
Given that:
val mockHttpClient = mock[THttpClient]
is properly injected into my class under test, the test code is something like this:
val expectedUrl = "some url"
val mockRequestHolder = mock[WSRequestHolder]
inSequence {
(mockHttpClient.url _).expects(expectedUrl).returns(mockRequestHolder)
(mockRequestHolder.withQueryString _).expects(where {
(parameters: Seq[(String, String)]) => {
// assertions on parameters
// ...
true
}
}).returns(mockRequestHolder)
val stubResponse = stub[WSResponse]
val jsonBody = "{}"
(stubResponse.json _).when().returns(Json.parse(jsonBody))
(mockRequestHolder.get _).expects().returns(Future(stubResponse))
}
IntelliJ is highlighting mockRequestHolder.get as an error saying: cannot resolve symbol get. Nevertheless I'm able to run the test but the mock is clearly not working, and I'm getting: java.util.NoSuchElementException: JsError.get.
The mock is working when I try to mock any other method of WSRequestHolder, but not with method get.
Is this a ScalaMock bug or am I doing something wrong?
I don't know if you have solved already the issue, but I have tried to do something similar recently and I kind of got it working with the following code:
val wsClientMock = mock[WSClient]
val wsRequestMock = mock[WSRequest]
val wsResponseMock = mock[WSResponse]
(wsRequestMock.withAuth _).expects(username, password, WSAuthScheme.BASIC).returning(wsRequestMock)
(wsRequestMock.get _).expects().returning(Future[WSResponse](wsResponseMock))
(wsClientMock.url _).expects(bootstrapUrl).returning(wsRequestMock)
(wsResponseMock.status _).expects().returning(200)
"kind of" because I need to mock also the response, otherwise I get results like
ERROR[default-akka.actor.default-dispatcher-4] OneForOneStrategy - Unexpected call: json()
due to the fact that the code calling the WSClient is calling the method .json of WSResponse.
Sorry, I don't know Scala Mock but I suggest you to have a look at MockWS a library which comes with a mocked WS client: play-mockws
With MockWS you define a partial function which returns an Action for a Route. This enables you to precisely configure mocked answers and test your http client code.

Akka message undelivered

I've a PropertiesStore actor that holds a mutable.Buffer of runtime configuration that's manipulated through a rest API. You read and write from said store using these objects:
Read(None, Property(key ="MyConfigKey", value = None))
to which the store responds with the Property and its value.
In order to ease the locating of this store, I have another actor (a cameo) that I create on the fly:
object PropertyLookup {
def apply(propertyKey: String, target: Option[ActorRef]): Props = {
Props(new PropertyLookup(propertyKey, target))
}
}
class PropertyLookup(key: String, target: Option[ActorRef]) extends Actor with ActorLogging {
val PropertiesStore = "/user/Master/DataStore/PropertiesStore"
val propertiesActor = context.actorSelection(PropertiesStore)
def receive: Actor.Receive = {
case _=>
log.info(s"Looking up ${key} via ${propertiesActor}")
propertiesActor.tell(Read(None, Property(key, None)), target.getOrElse(sender()))
log.info(s"Sent property lookup to PropertiesStore: ${key}")
// context.stop(self)
}
}
Which enables me to keep the "locating" of said actor (i.e. via its path) in one place, avoiding too much rework if it's moved. This PropertyLookup has an optional target actor that the PropertiesStore will send the result to once the lookup is performed. I use all this like so in another actor to get a config value before I do some work:
context.actorOf(PropertyLookup(PropertyKeys.SpreadsheetURL, None), s"PropertiesLookup_${self.path.name}") ! None
but when I do so, I get the following warning:
Message [domain.Read] from
Actor[akka://NN/user/$a/Master/DataStore/PlayerStore#-1100303450] to
Actor[akka://NN/user/Master/DataStore/PropertiesStore] was not
delivered. [2] dead letters encountered. This logging can be turned
off or adjusted with configuration settings 'akka.log-dead-letters'
and 'akka.log-dead-letters-during-shutdown'
and I never receive my Property instance in the callee. The cameo (instance of PropertyLookup) does do its stuff and log, so I know that part is working.
What's happening? Is my cameo all wrong? Any better ways to do this? How do I understand what's happening around this warning>
Is your code and log outputs up to date?
First you gave definition of Read as
Read(Property(key ="MyConfigKey", value = None))
but then you are using it as
Read(None, Property(key, None))
Secondly you are creating actor with "PropertiesLookup_${self.path.name}" in name. But your log output shows that this actor name doesn't contain "PropertiesLookup" string.
In addition, notice that your path as logged includes a $a which suggests that an anonymous actor is in fact in the path, which isn't what's in your actorSelection call.