I have a set of tests all of which require same code before each test, for this purpose I happily use BeforeAndAfterEach. I need to perform the set of tests a few times with different settings of the fixtures. To perform the tests several times I use test sharing with "should behave like" from FlatSpecLike. However, I don't see an elegant way to combine "should behave like" with BeforeAndAfterEach.
Currently I use the Tag-based method presented below. Quite ugly.
Question: is there a more elegant way to perform a set of tests under different settings that are used before each test in the set.
class TestSpec() extends FlatSpecLike with Matchers with BeforeAndAfterEachTestData {
// have to invent a tag with a name for each object of Settings
val TagNamePrefix = "MySettingsTag"
case object NormalTag extends Tag(TagNamePrefix+"Normal")
case object SpecialTag extends Tag(TagNamePrefix+"Special")
// and put them into a map by name
var settingsMap: String => Settings = Map (
NormalTag.name -> Settings(0, 0, someGlobalNormalObject),
SpecialTag.name -> Settings(10, 10, someGlobalSpecialObject)
)
override def beforeEach(testData: TestData) {
val s: Settings = retrieveSettings(testData)
// some code here depending on the settings
super.beforeEach(testData)
}
/** the ugly way to retrieve settings in beforeEach */
private def retrieveSettings(testData: TestData): Settings = {
val tags = testData.tags.filter(_.startsWith(TagNamePrefix))
assert(tags.size == 1)
settingsMap(tags.last)
}
"A thing" should behave like testSet(NormalTag)
"A thing with special settings" should behave like testSet(SpecialTag)
def testSet(t: Tag) {
it should "test something" taggedAs t in {
// ...
}
it should "test something else" taggedAs t in {
// ...
}
}
}
Related
I am trying to test
trait Name extends Helper {
def name() = {
var s = getSystem()
s.name()
}
}
where all I want to do is make sure that the "s.name()" method is invoked once by mocking an instance of s, which is a System.
Helper is defined as so:
trait Helper {
def getSystem() : System = {
systemGetter.get()
}
}
As of now, my NameSpec looks something like:
class NameSpec extends FlatSpec with Matchers with MockitoSugar {
class NameImpl extends Name
var toTest = new NameImpl
val mockSystem = mock[System]
it should "call s.name() once" in {
when(getSystem() is invoked, return a mockSystem)
toTest.name()
// Verify that mockSystem.name() happened only once
}
}
What I'm confused about is how to return a mock System in toTest.name() when it calls getSystem() so that I can verify that the system calls s.name() only once. I could easily mock this System if it were a parameter to the name() method in Name trait, so I guess I don't know how to "inject" a mockSystem to be used instead of a real system when that method is invoked.
Unfortunately your code is not compilable and thus is obviously an inadequate representation of what you really have. Particularly it is not clear how the Helper really gets an object of type System. I think that in the real code you should mock the systemGetter, that I suppose is somehow injected into the objects implementing Helper trait, to return your mockSystem. However it is hard to show you a valid example of that basing on the code you provided. If for some reason this is not what you can do, there are a few more avenues.
You seem to use something like Cake pattern around Helper and its inheritance. If so, you can use a class instead of NameImpl to inject System:
class NameWithInjectedSystem(val system: System) extends Name {
override def getSystem(): System = system
}
it should "call s.name() once" in {
val mockSystem = mock[System]
val nameToTest = new NameWithInjectedSystem(mockSystem)
val mockName = "Mock name"
when(mockSystem.name()).thenReturn(mockName)
val actual = nameToTest.name()
actual should === (mockName)
verify(mockSystem, times(1)).name()
}
Finally you can mock even nameToTest object itself but this is not the way I'd suggest because it binds test to much more implementation details than you should want:
it should "call s.name() once" in {
val mockSystem = mock[System]
val nameToTest = mock[NameImpl]
when(nameToTest.getSystem()).thenReturn(mockSystem)
when(nameToTest.name()).thenCallRealMethod()
val mockName = "Mock name"
when(mockSystem.name()).thenReturn(mockName)
val actual = nameToTest.name()
actual should ===(mockName)
verify(mockSystem, times(1)).name()
}
Note how you must call thenCallRealMethod for the .name() call and so you should do for all the calls inside the name or the test will not work.
I have a set of input cases stored in a file.
I would like each case to be a specific scalatest "test", i.e., reported in the console as an individual test and failed individually.
Unfortunately, experimentation and Google suggest that this capability might not be present?
E.g., this seems to be the common case (eliding for simplicity)
class MyTestingGoop extends FunSuite {
val input : Seq[SpecificTestCase] = ...
test("input data test") {
forAll(input) { case => ... }
}
//...
}
Ideally, each case presents as a separate test. How can this be done with ScalaTest?
You can do this:
class MyTestingGoop extends FunSuite {
val input : Seq[SpecificTestCase] = ...
forAll(input) {
test("testing input" + input) {
// do something with the test
}
}
}
The only limit is that input has a unique toString.
Basically calling test in Funsuite registers the test and later runs it so as long as your test creation is done as part of the class construction and each test has a unique string, you should be fine.
I have a test suite that implements BeforeAndAfter, and I'd ideally like to be able to check in my after() method if the test failed, and if it did calculate some value and print it out. Is there an inbuilt way of doing this?
ps. I know I can do a try/catch around the whole test but I'd rather not have to do that.
I don't think you can do it in after(), however you can do it by overriding withFixture(). This method runs the actual test, after that you can match the result and print something in case of failure:
class ExampleSpec extends WordSpec with MustMatchers {
"Example" must {
"work correctly" in {
3 must be(3)
}
"not fail" in {
true must be(false)
}
}
override def withFixture(test: NoArgTest) = super.withFixture(test) match {
case failed: Failed =>
val nameLen = test.name.length
info(s"The test '${test.name}' failed")
info(s"The test name is $nameLen characters long")
failed
case other => other
}
}
See Sharing Fixtures, especially the section "Overriding withFixture(NoArgTest)"
Depending on your needs, you can:
1) write something like def around[T](code: => T) = try {code} ... and use it like:
test("mytest") {
around {
}
}
it should "blabla" in around {
...
}
2) If you don't use specs then just write your own:
def mytest[T](name: String)(code: =>T) = test(name){
try {
code
} ...
}
or just override test:
override def test[T](name: String)(code: =>T) = super.test(name){
try {
code
} ...
}
Both can be done in separate trait, btw.
3) Override withFixture as it described #alextsc's answer
4) Write your own reporter if you want to intercept all tests in your build
P.S. BeforeAndAfter/withFixture are meant to clean up resources (that's why they don't give you any access to exception), so logically reporter solution might fit better if you need to analyze and rerepresent your errors, but it's not much convenient.
I'm using Play! 2.4 with Deadbolt2 for authorization. However, since I introduced the authorization rules, I'm unable to write successful tests for my controllers. As an example:
class VisitController #Inject() (authorization: DeadboltActions) extends Controller {
def fetchDailyVisits(date: Date) = authorization.Restrict(List(Array(ADMIN_ROLE), Array(MANAGER_ROLE))) {
Action.async {
visitService.findDailyVisits(date).map(result =>
Ok(Json.toJson(result))
)
}
}
}
I'm using specs2 in the tests. My test looks like this atm:
class VisitControllerSpec extends PlaySpecification with Mockito with ScalaFutures {
val deadboltActions = mock[DeadboltActions]
"VisitControllerSpec#fetchDailyVisits" should {
val testDate = Date.from(LocalDate.of(2016, 2, 25)
.atStartOfDay(ZoneId.systemDefault()).toInstant)
"Return Status Ok with returned list" in {
val expected = List(completeVisitWithId, anotherCompleteVisitWithId)
visitService.findDailyVisits(testDate) returns Future { expected }
val request = FakeRequest(GET, "/visits?date=2016-02-25")
val result = new VisitController(deadboltActions)
.fetchDailyVisits(testDate)(request)
result.futureValue.header.status must beEqualTo(OK)
contentAsJson(result) must_== Json.toJson(expected)
}
}
}
How do I mock deadboltActions in a way I can specify the user will be allowed access?
Is there another way? Maybe by providing a different DeadboltHandler? It seems kind of obvious this would be the way to go, I just don't seem to be able to figure it out and there aren't a lot of Deadbolt2 examples out there (at least for scala).
Or, being more extreme, any other authorization framework out there that works well with scala play and allows to handle security as a cross-cutting concern without poluting the controllers? Deadbolt2 is too limited for this reason, but I honestly can't find a better authorization framework (unless I write my own).
There are a number of different ways you can do this.
If your DeadboltHandler has a DAO injected for accessing the subject, you can override the binding of the DAO to provide one containing test subjects.
abstract class AbstractControllerSpec extends PlaySpecification {
sequential
isolated
def testApp: Application = new GuiceApplicationBuilder().in(Mode.Test).bindings(bind[SubjectDao].to[TestSubjectDao]).build()
}
See the test app for an example of using this approach.
Alternatively, you can extend your DeadboltHandler implementation to override getSubject and provide a test subject from here. The binding is handled in the same way as above.
Finally, you can keep all your code as-is and populate the test database with subjects; the requests you send will be shaped by your authentication requirements (headers, something in a cookie, etc).
For unit testing, something similar applies. Given a SubjectDao that has some hard-coded subjects for test purposes, you can use WithApplication and an injector look-up to get what you need.
class TestSubjectDao extends SubjectDao {
val subjects: Map[String, Subject] = Map("greet" -> new SecuritySubject("greet",
List(SecurityRole("foo"),
SecurityRole("bar")),
List(SecurityPermission("killer.undead.zombie"))),
"lotte" -> new SecuritySubject("lotte",
List(SecurityRole("hurdy")),
List(SecurityPermission("killer.undead.vampire"))),
"steve" -> new SecuritySubject("steve",
List(SecurityRole("bar")),
List(SecurityPermission("curator.museum.insects"))),
"mani" -> new SecuritySubject("mani",
List(SecurityRole("bar"),
SecurityRole("hurdy")),
List(SecurityPermission("zombie.movie.enthusiast"))),
"trippel" -> new SecuritySubject("trippel",
List(SecurityRole("foo"),
SecurityRole("hurdy")),
List[SecurityPermission]()))
override def user(userName: String): Option[Subject] = subjects.get(userName)
}
With a controller that looks something like this:
class Subject #Inject()(deadbolt: DeadboltActions) extends Controller {
def subjectMustBePresent = deadbolt.SubjectPresent()() { authRequest =>
Future {
Ok("Content accessible")
}
}
}
We can then unit test it like this:
import be.objectify.deadbolt.scala.DeadboltActions
import be.objectify.deadbolt.scala.test.controllers.composed.Subject
import be.objectify.deadbolt.scala.test.dao.{SubjectDao, TestSubjectDao}
import play.api.Mode
import play.api.inject._
import play.api.inject.guice.GuiceApplicationBuilder
import play.api.mvc.{Result, Results}
import play.api.test.{FakeRequest, PlaySpecification, WithApplication}
import scala.concurrent.Future
object SubjectPresentUnitSpec extends PlaySpecification with Results {
"Subject present " should {
"should result in a 401 when no subject is present" in new WithApplication(new GuiceApplicationBuilder().in(Mode.Test).bindings(bind[SubjectDao].to[TestSubjectDao]).build()) {
val deadbolt: DeadboltActions = implicitApp.injector.instanceOf[DeadboltActions]
val controller = new Subject(deadbolt)
val result: Future[Result] = call(controller.subjectMustBePresent(), FakeRequest())
val statusCode: Int = status(result)
statusCode must be equalTo 401
}
"should result in a 200 when a subject is present" in new WithApplication(new GuiceApplicationBuilder().in(Mode.Test).bindings(bind[SubjectDao].to[TestSubjectDao]).build()) {
val deadbolt: DeadboltActions = implicitApp.injector.instanceOf[DeadboltActions]
val controller = new Subject(deadbolt)
val result: Future[Result] = call(controller.subjectMustBePresent(), FakeRequest().withHeaders(("x-deadbolt-test-user", "greet")))
val statusCode: Int = status(result)
statusCode must be equalTo 200
}
}
}
It doesn't answer exactly to my original question, which was mostly related with Deadbolt2, but I kept getting frustrated with the fact I had to specify my authorization rules in my controllers, which is not truly cross cutting.
The answer provided by Steve Chaloner helps, but still forced me to go through a few hoops.
Enter Panoptes. This authorization framework is based on Filters instead of Action chaining, so it allows to easily specify authorization rules in a central location and outside of the controllers.
Setting your security rules in Panoptes is somewhat similar to Spring Security and it looks like this:
class BasicAuthHandler extends AuthorizationHandler {
override def config: Set[(Pattern, _ <: AuthorizationRule)] = {
Set(
Pattern(Some(POST), "/products") -> atLeastOne(withRole("Admin"), withRole("Manager"))
Pattern(Some(GET), "/cart[/A-Za-z0-9]*") -> withRole("Admin"),
Pattern(None, "/orders[/A-Za-z0-9]*") -> withRole("Admin")
)
}
}
Other than that, you need a couple of lines to declare the filter and plug in your AuthorizationHandler.
class Filters #Inject()(securityFilter: SecurityFilter) extends HttpFilters {
override def filters = Seq(securityFilter)
}
class ControllerProviderModule extends AbstractModule {
override def configure(): Unit = { bind(classOf[AuthorizationHandler]).to(classOf[MyAuthorizationHandler])
}
}
The README file in the git repository has more details and code samples.
It's also customizable to the point it allows to create your own AuthorizationRules. In my project I have a requirement where I need to check the mobile device that makes the call is registered in the system. I can write an AuthorizationRule to handle this for me for every request whose path matches my pattern.
Unit testing controllers is extra simple, because any mocking of the security layer can be ommited. They can be tested like any other class.
If you're having similar issues or also believe authorization rules don't belong in the controllers, have a go at Panoptes, it might suit your needs. Hope this helps someone else.
I have a number of test data sets that run through the same ScalaTest unit tests. I'd love if each test data set was it's own set of named tests so if one data set fails one of the tests i know exactly which one it was rather than going to a single test and looking on what file it failed. I just can't seem to find a way for the test name to be generated at runtime. I've looked at property and table based testing and currently am using should behave like to share fixtures, but none of these seem to do what I want.
Have I not uncovered the right testing approach in ScalaTest or is this not possible?
You can write dynamic test cases with ScalaTest like Jonathan Chow wrote in his blog here: http://blog.echo.sh/2013/05/12/dynamically-creating-tests-with-scalatest.html
However, I always prefer the WordSpec testing definitions and this also works with dynamic test cases just like Jonathan mentions.
class MyTest extends WordSpec with Matchers {
"My test" should {
Seq(1,2,3) foreach { count =>
s"run test $count" in {
count should be(count)
}
}
}
}
When running this test it run 3 test cases
TestResults
MyTest
My test
run test 1
run test 2
run test 3
ps. You can even do multiple test cases in the same foreach function using the same count variable.
You could write a base test class, and extend it for each data set. Something like this:
case class Person(name: String, age: Int)
abstract class MyTestBase extends WordSpec with Matchers {
def name: String
def dataSet: List[Person]
s"Data set $name" should {
"have no zero-length names" in {
dataSet.foreach { s => s.name should not be empty }
}
}
}
class TheTest extends MyTestBase {
override lazy val name = "Family" // note lazy, otherwise initialization fails
override val dataSet = List(Person("Mom", 53), Person("Dad", 50))
}
Which produces output like this:
TheTests:
Data set Family
- should have no zero-length names
You can use scala string substitutions in your test names. Using behavior functions, something like this would work:
case class Person(name: String, age: Int)
trait PersonBehaviors { this: FlatSpec =>
// or add data set name as a parameter to this function
def personBehavior(person: => Person): Unit = {
behavior of person.name
it should s"have non-negative age: ${person.age}" in {
assert(person.age >= 0)
}
}
}
class TheTest extends FlatSpec with PersonBehaviors {
val person = Person("John", 32)
personBehavior(person)
}
This produces output like this:
TheTest:
John
- should have non-negative age: 32
What about using ScalaTest's clue mechanism so that any test failures can report as a clue which data set was being used?
You can use the withClue construct provided by Assertions,
which is extended by every style trait in ScalaTest, to add
extra information to reports of failed or canceled tests.
See also the documentation on AppendedClues