ScalaTest: setup/tearDown methods for only selected tests - scala

I do know that there is the BeforeAndAfter trait which allows us to perform setup and tear-down operations before and after every test of a suite.
Is there an alternative that either runs only before and after a suite or runs for selected tests?

Regarding before and after particular test consider loan pattern
import org.scalactic.Equality
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
class LoanPatternExampleSpec extends AnyFlatSpec with Matchers {
def life(testFun: Int => Any): Unit = {
println("Doing stuff before the test")
val meaningOfLife = 42
testFun(meaningOfLife)
println("Doing stuff after the test")
}
"User" should "do things" in life { i =>
println(s"My fixture says meaning of life is $i")
assert(true)
}
}
which outputs
sbt:scalatest-seed> testOnly example.LoanPatternExampleSpec
Doing stuff before the test
My fixture says meaning of life is 42
Doing stuff after the test
[info] LoanPatternExampleSpec:
[info] User
[info] - should do things
[info] Run completed in 314 milliseconds.
[info] Total number of tests run: 1
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.
BeforeAndAfterAll has overrides for methods to be executed once before and after the suite.

Related

Sbt run tests from src/main/scala instead of src/test/scala?

Say I have a scalatest class in main/scala, like
import org.scalatest.FunSuite
class q3 extends FunSuite {
test("6 5 4 3 2 1") {
val digits = Array(6,5,4,3,2,1)
assert(digits.sorted === Array(1,2,3,4,5,6))
}
}
How do I run it with sbt?
I've tried sbt test, sbt testOnly, sbt "testOnly *q3" and they all had output like
[info] Run completed in 44 milliseconds.
[info] Total number of tests run: 0
[info] Suites: completed 0, aborted 0
[info] Tests: succeeded 0, failed 0, canceled 0, ignored 0, pending 0
[info] No tests were executed.
[info] No tests to run for Test / testOnly
A similar question from a few years back said they successfully used testOnly but I can't get it to work.
The metals extension on VSCode shows a "test" link when the file is open which successfully runs the test, but doesn't show how it does that. I want to know how to do it through sbt.
Put ScalaTest on Compile classpath in build.sbt like so
libraryDependencies += "org.scalatest" %% "scalatest" % "3.1.0"
and then call org.scalatest.run runner explicitly from within an App, for example,
object MainTests extends App {
org.scalatest.run(new ExampleSpec)
}
Putting it together we have in src/main/scala/example/MainTests.scala
package example
import org.scalatest.matchers.should.Matchers
import org.scalatest.flatspec.AnyFlatSpec
import collection.mutable.Stack
import org.scalatest._
class ExampleSpec extends AnyFlatSpec with Matchers {
"A Stack" should "pop values in last-in-first-out order" in {
val stack = new Stack[Int]
stack.push(1)
stack.push(2)
stack.pop() should be (2)
stack.pop() should be (1)
}
}
object MainTests extends App {
org.scalatest.run(new ExampleSpec)
}
and run it with runMain example.MainTests. Furthermore, we could gather tests in Suites and execute all like so
class ExampleASpec extends FlatSpec with Matchers {
"ExampleA" should "run" in { succeed }
}
class ExampleBSpec extends FlatSpec with Matchers {
"ExampleB" should "run" in { succeed }
}
class ExampleSuite extends Suites(
new ExampleASpec,
new ExampleBSpec,
)
object MainTests extends App {
(new ExampleSuite).execute()
}

Scala Play + Slick: How to inject dependencies to Spec tests?

I'm using Scala Play 2.7.x (the project is available here Play-Silhouette-Seed) and would like to test my daos. I have put together this simple one first to check what's the "new pattern" for testing play + slick + guice in 2.7.x:
package models.daos
import java.util.UUID
import org.specs2.mock._
import org.specs2.mutable._
import utils.AwaitUtil
import javax.inject.Inject
import models.generated.Tables.LoginInfoRow
class LoginInfoDaoSpec #Inject() (loginInfoDao: LoginInfoDao) extends Specification with Mockito with AwaitUtil {
"Creating a new LoginInfo" should {
"save it in the empty database" in {
loginInfoDao.create(LoginInfoRow(0, UUID.randomUUID().toString, UUID.randomUUID().toString))
loginInfoDao.findAll.size should beEqualTo(1)
}
}
}
Unfortunately, the guice dependency LoginInfoDao is not being provided to my test and then I get the error:
[play-silhouette-seed] $ testOnly models.daos.LoginInfoDaoSpec
[info] Done compiling.
[error] Can't find a suitable constructor with 0 or 1 parameter for class models.daos.LoginInfoDao
[info] ScalaTest
[info] Run completed in 1 second, 966 milliseconds.
[info] Total number of tests run: 0
[info] Suites: completed 0, aborted 0
[info] Tests: succeeded 0, failed 0, canceled 0, ignored 0, pending 0
[info] No tests were executed.
[error] Error: Total 1, Failed 0, Errors 1, Passed 0
How do I get guice loading the needed modules for my test-cases?
A module is defined as:
class SilhouetteModule extends AbstractModule with ScalaModule {
override def configure() {
// ...
bind[LoginInfoDao].to[LoginInfoDaoImpl]
// ...
}
}
and I have an application.test.conf available defined as:
include "application.conf"
slick.dbs {
default {
profile="slick.jdbc.MySQLProfile$"
db.driver="com.mysql.cj.jdbc.Driver"
db.url="jdbc:mysql://localhost:3306/mytestdb?useUnicode=true&searchpath=public&serverTimezone=CET"
db.user="dev"
db.password="12345"
}
}
You should use another database for testing, H2 is the common choice.
class Module extends AbstractModule with ScalaModule {
...
}
With that name you need to let play know there is a Module to load, if you call it Module, it automatically know what to load and should work just fine (if you only need 1 module in testing)
If that doesn't work let me know

Property check should fail in Scalatest

I've created and am also using some external Scalacheck generators from Lists and appropriate types, using Gen.oneOf(List[T]) . I think it would be occasionally useful to return a placeholder for an empty value. Currently the lists are populated. How should I go about this? Do I try to append an empty type to the end of the list? If so how do I go about that? If not, how else can I get my generators to add an empty value. It seems straightforward, but I am having trouble figuring it out right now.
import org.scalatest.FlatSpec
import org.scalacheck.Gen
import org.scalacheck.Prop.exists
import org.scalatest.prop.PropertyChecks
class EventFieldGeneratorTest extends FlatSpec with PropertyChecks {
behavior of "Gen.option"
it should "occasionally return None" in {
val colors = Gen.oneOf("Blue", "Red", "Green", "Yellow")
val opt = Gen.option(colors)
val list = Gen.listOfN(20, opt)
val p1 = exists(list)(_ == None)
p1.check
}
}
Can anybody explain why my test is giving up?
Testing started at 10:31 AM ... ! Gave up after only 0 passed tests. 501 tests were discarded.
Process finished with exit code 0
How can I mark that as a failed result for ScalaTest? Is it a bad idea for me to use Flatspec?
Maybe I should be using something other than check...
Here's the documentation I used to sort it on. On the Scalatest page:
http://www.scalatest.org/user_guide/writing_scalacheck_style_properties
I don't think there's anything flawed with trying to use lists with optional values. There are just a few issues you're running in to that are giving you trouble.
It's confusing, but if you're using the Scalatest framework, you need to use the Scalatest infrastructure to use Scalacheck. So you'll need to use Scalatest matchers, and write Scalatest-flavored properties (using it's forAll), but you'll still use Scalacheck's generators directly.
For some reason the type inference between lists and Option type is giving you trouble. If you use the shouldBe matcher,
x shouldBe(None)
you'll get a relevant runtime error from Scalatest:
[info] - should occasionally return None *** FAILED ***
[info] TestFailedException was thrown during property evaluation.
[info] Message: List() was not equal to None
[info] Location: (GenTest.scala:13)
[info] Occurred when passed generated values (
[info] arg0 = List() // 5 shrinks
[info] )
[info] Run completed in 1 second, 621 milliseconds.
[info] Total number of tests run: 1
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 0, failed 1, canceled 0, ignored 0, pending 0
You shouldn't be matching a list with an Option type. You need to be matching with the Scalatest "container" matcher should contain
import org.scalatest.FlatSpec
import org.scalatest.Matchers
import org.scalacheck.Gen
import org.scalatest.prop.PropertyChecks
class EventFieldGeneratorTest extends FlatSpec with Matchers with PropertyChecks {
behavior of "Gen.option"
it should "occasionally return None" in {
val colors = Gen.oneOf("Blue","Red","Green","Yellow")
val opt = Gen.option(colors)
val list = Gen.listOfN(20,opt)
forAll(list) { (xs: List[Option[String]]) =>
xs should contain (None)
}
}
}
This gives you a successful property check:
[info] EventFieldGeneratorTest:
[info] Gen.option
[info] - should occasionally return None
[info] ScalaTest
[info] Run completed in 1 second, 9 milliseconds.
[info] Total number of tests run: 1
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.
[info] Passed: Total 1, Failed 0, Errors 0, Passed 1
More on Scalatest matchers
http://www.scalatest.org/user_guide/using_matchers

ScalaCheck specificy minimum successful tests for property

I'm trying to make sure that my ScalaCheck property runs 500 times instead of the default 100 times. I'm having trouble configuring this though.
class BlockSpec extends Properties("BlockSpec") with BitcoinSLogger {
val myParams = Parameters.default.withMinSuccessfulTests(500)
override def overrideParameters(p: Test.Parameters) = myParams
property("Serialization symmetry") =
Prop.forAll(BlockchainElementsGenerator.block) { block =>
logger.warn("Hex:" + block.hex)
Block(block.hex) == block
}
}
However when I actually run this test it only says 100 tests passed successfully
EDIT:
$ sbt
[info] Loading project definition from /home/chris/dev/bitcoins-core/project
[info] Set current project to bitcoin-s-core (in build file:/home/chris/dev/bitcoins-core/)
> test-only *BlockSpec*
[info] + BlockSpec.Serialization symmetry: OK, passed 100 tests.
[info] Elapsed time: 1 min 59.775 sec
[info] ScalaCheck
[info] Passed: Total 1, Failed 0, Errors 0, Passed 1
[info] ScalaTest
[info] Run completed in 2 minutes.
[info] Total number of tests run: 0
[info] Suites: completed 0, aborted 0
[info] Tests: succeeded 0, failed 0, canceled 0, ignored 0, pending 0
[info] No tests were executed.
[info] Passed: Total 1, Failed 0, Errors 0, Passed 1
[success] Total time: 123 s, completed Aug 1, 2016 11:36:17 AM
>
How do I actually pass this to my property?
As far as I understand you can specify the test parameters at two levels and they don't seem to communicate.
The first option is within the property as you're trying to do:
import org.scalacheck.Properties
import org.scalacheck.Test.{ TestCallback, Parameters }
import org.scalacheck.Prop.{ forAll, BooleanOperators }
import org.scalacheck.Test
class TestFoo extends Properties("BlockSpec") {
override def overrideParameters(p: Parameters) =
p.withMinSuccessfulTests(1000000)
property("Serialization symmetry") = forAll { n: Int =>
(n > 0) ==> (math.abs(n) == n)
}
}
This will have no impact as long as you don't call .check on the property.
Can be from the sbt shell or directly within the class.
Now if you want to impact the number of tests run when calling the sbt:test target, it seems you have to play with options build.sbt (taken from here):
name := "scalacheck-demo"
scalaVersion := "2.11.5"
libraryDependencies += "org.scalacheck" %% "scalacheck" % "1.12.2" % "test"
testOptions in Test += Tests.Argument(TestFrameworks.ScalaCheck, "-maxSize", "5", "-minSuccessfulTests", "33", "-workers", "1", "-verbosity", "1")
There's definitely an easier way to achieve that than overriding any kind of global test config:
class SampleTest extends FlatSpec
with Matchers with GeneratorDrivenPropertyChecks {
it should "work for a basic scenario" in {
// This will require 500 successful tests to succeed
forAll(minSuccessful(500)) { (d: String) =>
whenever (d.nonEmpty) {
d.length shouldBe > 0
}
}
}
}

Request was neither completed nor rejected within 1 second Scala Spray Testing

I currently testing a web service, and I keep on running into an error where the web service test is failing because it is timing out. I'm trying to extends that timeout to be 5 seconds long. I'm trying to mimic a solution that some one posted on the Scala Spray google groups forum to no avail. Here is the code I am trying to use in my test:
import akka.testkit._
import akka.actor.ActorSystem
import com.github.nfldb.config.{NflDbApiActorSystemConfig, NflDbApiDbConfigTest}
import org.scalatest.MustMatchers
import org.specs2.mutable.Specification
import spray.testkit.Specs2RouteTest
import spray.routing.HttpService
import spray.http.StatusCodes._
import spray.json.DefaultJsonProtocol._
import spray.httpx.SprayJsonSupport._
import concurrent.duration._
/**
* Created by chris on 8/25/15.
*/
class NflPlayerScoringSvcTest extends Specification with Specs2RouteTest with NflPlayerScoringService
with NflDbApiDbConfigTest with NflDbApiActorSystemConfig {
import PlayerScoreProtocol.playerScoreProtocol
implicit def actorRefFactory = actorSystem
implicit def default(system: ActorSystem = actorSystem) = RouteTestTimeout(new DurationInt(5).second.dilated)
"NflPlayerScoringSvc" should {
"return hello" in {
Get("/hello") ~> nflPlayerScoringServiceRoutes ~> check {
responseAs[String] must contain("Say hello")
}
}
"calculate a player's score for a given week" in {
import PlayerScoreProtocol.playerScoreProtocol
Get("/playerScore?playerId=00-0031237&gsisId=2015081551") ~> nflPlayerScoringServiceRoutes ~> check {
val playerScore : DfsNflScoringEngineComponent.PlayerScore = responseAs[DfsNflScoringEngineComponent.PlayerScore]
playerScore.playerId must be ("00-0031237")
}
}
}
}
and here is the error that I am receiving:
> test-only *NflPlayerScoringSvcTest*
[info] Compiling 1 Scala source to /home/chris/dev/suredbits-dfs/target/scala-2.11/test-classes...
15:54:54.639 TKD [com-suredbits-dfs-nfl-scoring-NflPlayerScoringSvcTest-akka.actor.default-dispatcher-4] INFO akka.event.slf4j.Slf4jLogger - Slf4jLogger started
15:54:55.158 TKD [NflDbApiActorSystemConfig-akka.actor.default-dispatcher-2] INFO akka.event.slf4j.Slf4jLogger - Slf4jLogger started
15:54:55.228 TKD [NflDbApiActorSystemConfig-akka.actor.default-dispatcher-2] INFO test test test - Trying to find score for player: 00-0031237 and optional gsisId: Some(2015081551)
15:54:55.228 TKD [NflDbApiActorSystemConfig-akka.actor.default-dispatcher-2] INFO test test test - Searching for player 00-0031237 with optional game: Some(2015081551)
15:54:55.268 TKD [NflDbApiActorSystemConfig-akka.actor.default-dispatcher-4] INFO c.s.d.n.s.NflPlayerScoringSvcTest - Creating database for class com.suredbits.dfs.nfl.scoring.NflPlayerScoringSvcTest
[info] NflPlayerScoringSvcTest
[info]
[info] NflPlayerScoringSvc should
[info] + return hello
[info] x calculate a player's score for a given week
[error] Request was neither completed nor rejected within 1 second (NflPlayerScoringSvcTest.scala:33)
[info]
[info]
[info] Total for specification NflPlayerScoringSvcTest
[info] Finished in 1 second, 310 ms
[info] 2 examples, 1 failure, 0 error
[info] ScalaTest
[info] Run completed in 3 seconds, 455 milliseconds.
[info] Total number of tests run: 0
[info] Suites: completed 0, aborted 0
[info] Tests: succeeded 0, failed 0, canceled 0, ignored 0, pending 0
[info] No tests were executed.
[error] Failed: Total 2, Failed 1, Errors 0, Passed 1
[error] Failed tests:
[error] com.suredbits.dfs.nfl.scoring.NflPlayerScoringSvcTest
[error] (test:testOnly) sbt.TestsFailedException: Tests unsuccessful
[error] Total time: 11 s, completed Aug 25, 2015 3:54:56 PM
> 15:54:56.799 TKD [NflDbApiActorSystemConfig-akka.actor.default-dispatcher-2] INFO c.s.d.n.s.NflPlayerScoringSvcTest - Calculating score for game: NflGame(2015081551,Some(56772),2015-08-16T00:00:00.000Z,NflPreSeasonWeek1,Saturday,2015,Preseason,true,HomeTeam(MIN,26,9,14,3,0,2),AwayTeam(TB,16,3,6,7,0,1),2015-05-22T21:54:43.143Z,2015-08-16T17:29:01.729Z) and player: NflPlayer(00-0031237,Some(T.Bridgewater),Some(Teddy Bridgewater),Some(Teddy),Some(Bridgewater),MIN,QB,Some(2543465),Some(http://www.nfl.com/player/teddybridgewater/2543465/profile),Some(5),Some(11/10/1992),Some(Louisville),Some(2),Some(74),Some(215),Active)
can anyone provide any insight as what to what I can do to extend the time timeout time on Scala Spray?
Here is the solution
implicit def default(implicit system: ActorSystem) = RouteTestTimeout(new DurationInt(5).second.dilated(system))
I have to explicitly pass for system parameter to the dilated method because of implicit conflicts in Scala.
Similar to the previous answer, but a bit shorter
implicit def default(implicit system: ActorSystem) = RouteTestTimeout(5.seconds)
Here is the change which you will need to make -
implicit def default(implicit system: ActorSystem): RouteTestTimeout = RouteTestTimeout(new DurationInt(8).second.dilated(system))