How can I skip a "should" block/fragment in specs2? - scala

Suppose I have a specs2 specification defined in the "unit" style as follows:
import org.specs2.mutable
class MyClassSpec extends mutable.Specification {
"myMethod" should {
"return positive values" in {
MyClass.myMethod must beGreaterThan(0)
}
"return values less than 100" in {
MyClass.myMethod must beLessThan(100)
}
}
}
Is there an easy way to skip/disable/mark pending all of the examples within the should block/fragment for myMethod?
Obviously I can call pendingUntilFixed or return pending from each individual example in the block, but this would be rather tedious for a block with many specifications.
It seems like this would be a common occurrence if MyClass.myMethod is difficult to implement and gets punted. Is there another way that this is commonly done in specs2?

You can mix in the Tags trait and define any section you want:
import org.specs2.mutable._
class MyClassSpec extends Specification with Tags {
section("pending")
"myMethod" should {
"return positive values" in {
MyClass.myMethod must beGreaterThan(0)
}
"return values less than 100" in {
MyClass.myMethod must beLessThan(100)
}
}
section("pending")
}
Then you run your specification with exclude pending
>test-only *MyClassSpec* -- exclude pending
This is documented here.
You can also use an implicit context to make sure that all your examples in the should block are PendingUntilFixed:
import org.specs2._
import execute._
class MyClassSpec extends mutable.Specification {
"this doesn't work for now" >> {
implicit val puf = pendingContext("FIXME")
"ex1" in ko
"ex2" in ok
}
"but this works ok" >> {
"ex3" in ko // maybe not here ;-)
"ex4" in ok
}
def pendingContext(reason: String) = new mutable.Around {
def around[T <% Result](t: =>T) =
t.pendingUntilFixed(reason)
}
}
Update for specs2 3.x
import org.specs2._
import execute._
class TestMutableSpec extends mutable.Specification {
"this doesn't work for now" >> {
implicit def context[T] = pendingContext[T]("FIXME")
"ex1" in ko
"ex2" in ok
}
"but this works ok" >> {
"ex3" in ko // maybe not here ;-)
"ex4" in ok
}
def pendingContext[T](reason: String): AsResult[MatchResult[T]] =
new AsResult[MatchResult[T]] {
def asResult(t: =>MatchResult[T]): Result =
AsResult(t).pendingUntilFixed(reason)
}
}

Related

Reuse mock declaration across tests

I'd like to reuse mock declarations accross tests (if possible).
Here is a minimal non-working example using ScalaTest and Mockito. I'm expecting the ​yes​ value in the first test but I get the ​other​ value.
It seems that the latest Mockito.when is the one applied for all test clauses.
Is there a way to avoid declaring mocks in each in clause?
import org.mockito.Mockito._
import org.scalatest.mock.MockitoSugar
import org.scalatest.{Matchers, WordSpec}
​
class ReuseMocksSpec extends WordSpec with Matchers with MockitoSugar {
"A test" when {
val service = mock[Service]
"sharing mocks among tests" should {
when(service.getVal).thenReturn("yes")
"get yes value" in {
service.getVal should be("yes")
}
}
"sharing mocks among other tests" should {
when(service.getVal).thenReturn("other")
"get other value" in {
service.getVal should be("other")
}
}
}
​
trait Service {
def getVal: String
}
}
I reviewed the way I designed it and am now using a function to build my mocks:
def withValue(value: String)(body: (Service => String)) = {
val service = mock[Service]
when(service.getVal).thenReturn(value)
body(service)
}
The test class would become:
import org.mockito.Mockito._
import org.scalatest.mock.MockitoSugar
import org.scalatest.{Matchers, WordSpec}
class ReuseMocksSpec extends WordSpec with Matchers with MockitoSugar {
"A test" when {
"sharing mocks among tests" should {
"get yes value" in {
val value = withValue("yes") { service =>
service.getVal
}
value should be("yes")
}
}
"sharing mocks among other tests" should {
"get other value" in {
val value = withValue("other") { service =>
service.getVal
}
value should be("other")
}
}
}
def withValue(value: String)(body: (Service => String)) = {
val service = mock[Service]
when(service.getVal).thenReturn(value)
body(service)
}
trait Service {
def getVal: String
}
}
I don't know if it's the cleanest and easiest way to do it but it works...

ScalaTest test name without fixture?

First off, I saw it and this other post sounds exactly like what I need except for one thing, I can't use fixture.TestDataFixture because I can't extend fixture.FreeSpecLike, and I am sure that there must be some way to get the test name in a way that looks more like this (imagined code that doesn't compile)
class MySpec extends FlatSpecLike with fixture.TestDataFixture {
"this technique" - {
"should work" in {
assert(testData.name == "this technique should work")
}
"should be easy" in { td =>
assert(testData.name == "this technique should be easy")
}
}
}
Any ideas? I just can't believe something like this is not possible :D
While you already came to basically this solution, here is a safer variation:
private val _currentTestName = new ThreadLocal[String]
override def withFixture(test: NoArgTest) = {
_currentTestName.set(test.name)
val outcome = super.withFixture(test)
_currentTestName.set(null)
outcome
}
protected def currentTestName: String = {
val testName = _currentTestName.get()
assert(testName != null, "currentTestName should only be called in a test")
testName
}
Alternately,
protected def currentTestName = Option(_currentTestName.get())
You can find sequence of test names using method testNames in FlatSpecLike trait:
import org.scalatest.FlatSpecLike
class FooSpec extends FlatSpecLike {
it should "check case one" in {
println("test some code ...")
println(testNames.mkString("\n"))
/*
prints:
should check case one
should check case two
*/
// ...
assert(1 == 1)
println("end.")
}
it should "check case two" in {
println("test some code ...")
assert(1 == 1)
println("end.")
}
}
and find each you needed. Hope it helps.
And found an answer(well a collegue did), not sure I like it but works:
on the trait that other tests depend on
class MySpec extends FlatSpecLike {
//... other stuff
var testName = "UndefinedTestName"
override def withFixture (test: NoArgTest) :Outcome= {
testName = test.name
super.withFixture(test)
}
}
simple solution but rather obscure, also I wonder if anyone sees any problems with it

How to test methods that return Future?

I'd like to test a method that returns a Future. My attempts were as follows:
import org.specs2.mutable.Specification
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Failure, Success}
class AsyncWebClientSpec extends Specification{
"WebClient when downloading images" should {
"for a valid link return non-zero content " in {
val testImage = AsyncWebClient.get("https://www.google.cz/images/srpr/logo11ww.png")
testImage.onComplete { res =>
res match {
case Success(image) => image must not have length(0)
case _ =>
}
AsyncWebClient.shutDown
}
}
}
}
Apart from the fact that I am unable to make this code work I guess that there could be a better way of testing a futures with a Future-oriented matcher.
How to do it properly in specs2?
You can use the Matcher.await method to transform a Matcher[T] into a Matcher[Future[T]]:
val testImage: Future[String] =
AsyncWebClient.get("https://www.google.cz/images/srpr/logo11ww.png")
// you must specify size[String] here to help type inference
testImage must not have size[String](0).await
// you can also specify a number of retries and duration between retries
testImage must not have size[String](0).await(retries = 2, timeout = 2.seconds)
// you might also want to check exceptions in case of a failure
testImage must throwAn[Exception].await
Took me awhile to find this so thought I'd share. I should've read the release notes. In specs2 v3.5, it is required to use implicit ExecutionEnv to use await for future. This can also be used for future transformation (i.e. map) see http://notes.implicit.ly/post/116619383574/specs2-3-5.
excerpt from there for quick reference:
import org.specs2.concurrent.ExecutionEnv
class MySpec extends mutable.Specification {
"test of a Scala Future" >> { implicit ee: ExecutionEnv =>
Future(1) must be_>(0).await
}
}
Await is an anti pattern. Shouldn't ever use it.
You can use traits like ScalaFutures, IntegrationPatience, and Eventually.
whenReady does the magic you are looking for.
Example:
import org.specs2.mutable.Specification
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Failure, Success}
import org.scalatest.concurrent.{IntegrationPatience, ScalaFutures}
import scala.concurrent.Future
class AsyncWebClientSpec extends Specification
with ScalaFutures
with IntegrationPatience {
"WebClient when downloading images" should {
"for a valid link return non-zero content " in {
whenReady(Future.successful("Done")){ testImage =>
testImage must be equalTo "Done"
// Do whatever you need
}
}
}
}
There is a nice thing for that in specs2 - implicit await method for Future[Result]. If you take advantage of future transformations you can write like this:
"save notification" in {
notificationDao.saveNotification(notification) map { writeResult =>
writeResult.ok must be equalTo (true)
} await
}
Future composition comes to the rescue when some data arrangement with async functions is needed:
"get user notifications" in {
{
for {
_ <- notificationDao.saveNotifications(user1Notifications)
_ <- notificationDao.saveNotifications(user2Notifications)
foundUser1Notifications <- notificationDao.getNotifications(user1)
} yield {
foundUser1Notifications must be equalTo (user1Notifications)
}
} await
}
Note how we have to use an additional block around for-comprehension to convince compiler. I think it's noisy, so if we turn await method in a function we come up with a nicer syntax:
def awaiting[T]: Future[MatchResult[T]] => Result = { _.await }
"get user notifications" in awaiting {
for {
_ <- notificationDao.saveNotifications(user1Notifications)
_ <- notificationDao.saveNotifications(user2Notifications)
foundUser1Notifications <- notificationDao.getNotifications(user1)
} yield {
foundUser1Notifications must be equalTo (user1Notifications)
}
}
Wondering why #etorreborre did not mention "eventually"
See https://github.com/etorreborre/specs2/blob/master/tests/src/test/scala/org/specs2/matcher/EventuallyMatchersSpec.scala#L10-L43
class EventuallyMatchersSpec extends Specification with FutureMatchers with ExpectationsDescription { section("travis")
addParagraph { """
`eventually` can be used to retry any matcher until a maximum number of times is reached
or until it succeeds.
""" }
"A matcher can match right away with eventually" in {
1 must eventually(be_==(1))
}
"A matcher can match right away with eventually, even if negated" in {
"1" must not (beNull.eventually)
}
"A matcher will be retried automatically until it matches" in {
val iterator = List(1, 2, 3).iterator
iterator.next must be_==(3).eventually
}
"A matcher can work with eventually and be_== but a type annotation is necessary or a be_=== matcher" in {
val option: Option[Int] = Some(3)
option must be_==(Some(3)).eventually
}
onComplete returns Unit, so that block of code returns immediately and the test ends before being able to do anything. In order to properly test the result of a Future, you need to block until it completes. You can do so using Await, and setting a maximum Duration to wait.
import scala.concurrent._
import scala.concurrent.duration._
Await.result(testImage, Duration("10 seconds")) must not have length(0)

How to set vals to be used in tests?

I've been noticing a lot of repetition to set up each test with Play/specs2. I'm aware that you can create a trait that extends mutable.Before and use that to set up tests but any values created there seem to be out of scope for my tests.
What I would like to be able to do is set val user = User.create("User Name") in a class or trait before each test runs so I can have access to user later on in the test. How can this be achieved?
// SpecificationWithFixtures.scala
package models
import org.specs2.execute.{AsResult, Result}
import org.specs2.mutable._
import play.api.test.Helpers._
import play.api.test._
abstract class SpecificationWithFixtures extends Specification {
abstract class WithFakeDB extends WithApplication(FakeApplication(additionalConfiguration = inMemoryDatabase())) {
override def around[T: AsResult](t: => T): Result = super.around {
t
}
}
}
// UserSpec.scala
package models
import org.junit.runner._
import org.specs2.runner._
#RunWith(classOf[JUnitRunner])
class UserSpec extends SpecificationWithFixtures {
"User.create" should {
"save user in the database" in new WithFakeDB {
val user = User.create("User Name")
// Some test for user
}
}
"User.findAll" should {
"return a list of all users" in new WithFakeDB {
val user = User.create("User Name")
// Another test for user
}
}
}
What you can do is something like:
def withUser[T](test: User => T): T = test(User create "Username")
// or even more configurable
def withUser[T](name: String)(test: User => T): T = test(User create name)
// Then writing expectations you can do
"User Roger" in withUser("Roger") {
roger => // trivial example
roger.name must_== "Roger"
}
// or even
"User" in withUser("John") {
_.name must_== "John"
}
This kind of loan pattern is useful writing specs2.
In previous example it's user per expectation (in), but it can be used for a group of expectations (should, >>), or for all.
"User" should withUser("xyz") {
"exp1" in { ??? }
}

Specs2 - close JDBC connection after each test case

I implemented specs2 specification that looks something like this:
class MySpec extends Specification {
"My database query" should {
"return some results " in {
val conn = createJdbcConn()
try {
// matcher here...
} finally {
conn.close()
}
}
}
This ugly boilerplate is repeated in all my test cases. I have to open (and then close) a new connection for each in.
What is the idiomatic way in Specs2 close resources such as in this case - perhaps using the After (or BeforeAfter) trait to properly close the connection?
Another option is to use the FixtureExample trait introduced in 2.0, to avoid using a variable:
import org.specs2._
import specification._
import execute._
trait DbFixture extends FixtureExample[JdbcConnection] {
// type alias for more concise code
type DBC = JdbcConnection
/**
* open the connection, call the code, close the connection
*/
def fixture[R : AsResult](f: JdbcConnection => R): Result = {
val connection = createJdbcConnection
try AsResult(f(connection))
finally connection.close
}
}
class MySpec extends Specification with DbFixture {
"My database query" should {
"return some results" in { connection: DBC =>
// do something with the connection
success
}
}
}
It might be easiest to use a trait, and then your tests that need a db connection can just extend the trait (I'm not thrilled about the var, but it's the easiest way to do this):
trait DbTestLifeCycle extends BeforeAfterExample {
var dbConn:Option[YourDbConnection] = None
protected def before: Any = {
dbConn = Option(createJdbcConn())
}
protected def after: Any = {
dbConn.map(_.close())
}
}
So your test would look like this:
class MySpec extends Specification with DbTestLifeCycle {
"My database query" should {
"return some results " in {
dbConn.map(conn => //do something in the db)
// matcher here...
}
}
}