I'm in a situtation where I have 2 traits extending BeforeAfterAll doing different actions for integration tests: One managing the database and the other the file system. For example:
trait DBSpecification extends BeforeAfterAll {
override def beforeAll() = {
println("DB -> BeforeAll")
}
override def afterAll() = {
println("DB -> AfterAll")
}
}
trait FileSystemSpecification extends BeforeAfterAll {
override def beforeAll() = {
println("FileSystem -> BeforeAll")
}
override def afterAll() = {
println("FileSystem -> AfterAll")
}
}
class MyTest extends Specification with DBSpecification with FileSystemSpecification {
"some test" in {
1 ==== 1
}
}
If I do like this, only the prints of the last trait are executed, in this case FileSystemSpecification. If I try calling super from the traits, I start having some compilation problems. I've tried already a bunch of ways, but couldn't figure out the solution.
ScalaTest has some examples on its documentation, but couldn't find a way with Specs2.
Any ideas?
Yes traits are not the best thing for composing behaviour. Here is the boilerplaty way to do it:
import org.specs2.mutable._
import org.specs2.specification._
trait DBSpecification extends BeforeAfterAll {
def beforeAll() = {
println("DB -> BeforeAll")
}
def afterAll() = {
println("DB -> AfterAll")
}
}
trait FileSystemSpecification extends BeforeAfterAll {
def beforeAll() = {
println("FileSystem -> BeforeAll")
}
def afterAll() = {
println("FileSystem -> AfterAll")
}
}
trait FileSystemDBSpecification extends DBSpecification with FileSystemSpecification {
override def beforeAll() = {
super[DBSpecification].beforeAll()
super[FileSystemSpecification].beforeAll()
}
override def afterAll() = {
super[DBSpecification].afterAll()
super[FileSystemSpecification].afterAll()
}
}
class MyTestSpec extends Specification with FileSystemDBSpecification {
"some test" in {
1 ==== 1
}
}
Related
Consider the following minimal viable self contained testcase for BeforeAndAfter and BeforeAndAfterAll:
import org.scalatest.{BeforeAndAfter, BeforeAndAfterAll, FunSuite}
class BeforeAndAfterTestTest extends FunSuite with BeforeAndAfter with BeforeAndAfterAll {
override protected def beforeAll(): Unit = println("beforeAll")
override protected def afterAll(): Unit = println("afterAll")
override protected def before(fun: => Any)(implicit pos: Position): Unit = {
println("before")
}
override protected def after(fun: => Any)(implicit pos: Position): Unit = {
println("after")
}
test("hello1") { println("hello1") }
test("hello2") { println("hello2") }
}
The result of running this through scalatest is:
So :
The before/afterAll do execute
The before/after do not
What is needed to have the before and after methods get invoked?
You are supposed to call before and after, not override them:
import org.scalatest.{BeforeAndAfter, BeforeAndAfterAll, FunSuite}
class BeforeAndAfterTestTest extends FunSuite with BeforeAndAfter with BeforeAndAfterAll {
override protected def beforeAll(): Unit = println("beforeAll")
override protected def afterAll(): Unit = println("afterAll")
before {
println("before")
}
after {
println("after")
}
test("hello1") { println("hello1") }
test("hello2") { println("hello2") }
}
See the documentation here
If you want overrideable methods, you should use BeforeAndAfterEach, not BeforeAndAfter (doc)
Here's the example:
class A {
def postStop() {
println("A.postStop")
}
}
class B extends A with C {
override def postStop() {
println("B.postStop")
}
}
trait C { this: B =>
override def postStop() { // here I expected a warning
println("C.postStop")
}
}
object Main {
def main(args: Array[String]) {
new A().postStop()
}
}
This code prints B.postStop, and C.postStop override is silently ignored. Why is no warning printed? Is that a bug or a feature?
In this case it's not possible to issue a warning, because the compiler can't be sure that C.postStop() is never invoked. There can be another class defined somewhere, that extends B and C and explicitly calls C.postStop():
class D extends B with C {
override def postStop() {
super[C].postStop()
}
}
And this will invoke C.postStop() when you use it:
scala> D().postStop()
C.postStop
I have the following scala code. I don't understand why the implicit is not being figured by the compiler. I also tried putting the import line inside Main. Note however that when the implicit object was created inside Main, then the code ran correctly
import LoggingAddon._
object Main {
def main(args: Array[String]): Unit = {
val dog = new Dog
Util.act(dog)
}
}
class Dog {
def bark(): Unit = {
println("woof")
}
}
trait Action[A] {
def action(x: A): Unit
}
trait WithoutLogging[A] extends Action[A] {
}
trait WithLogging[A] extends Action[A] {
}
object LoggingAddon {
implicit object DogWithLogging extends WithLogging[Dog] {
override def action(x: Dog): Unit = {
println("before")
x.bark()
print("after")
}
}
}
object NoLoggingAddion {
implicit object DogWithoutLogging extends WithoutLogging[Dog] {
override def action(x: Dog): Unit = {
x.bark()
}
}
}
object Util {
def act(x: Dog)(implicit nolog: Action[Dog]): Unit = {
nolog.action(x)
}
}
I have imported the necessary implicit from the LoggingAddon but still the scala compiler says could not find implicit Action[Dog]
All I'm trying to do is make a pluggable typeclass. Rather than changing any piece of code, merely change the import statements to have different side effects
Simply move the order of usage where implicit is imported, I moved to the bottom in following example
class Dog {
def bark(): Unit = {
println("woof")
}
}
trait Action[A] {
def action(x: A): Unit
}
trait WithoutLogging[A] extends Action[A] {
}
trait WithLogging[A] extends Action[A] {
}
object LoggingAddon {
implicit object DogWithLogging extends WithLogging[Dog] {
override def action(x: Dog): Unit = {
println("before")
x.bark()
print("after")
}
}
}
object NoLoggingAddion {
implicit object DogWithoutLogging extends WithoutLogging[Dog] {
override def action(x: Dog): Unit = {
x.bark()
}
}
}
object Util {
def act(x: Dog)(implicit nolog: Action[Dog]): Unit = {
nolog.action(x)
}
}
import LoggingAddon._
object Main {
def main(args: Array[String]): Unit = {
val dog = new Dog
Util.act(dog)
}
}
class generator(options: Map[String, Any]) {
trait for_module extends abstractModule {
//generates trait with params
}
class my_module extends abstractModule with for_module
def exec = {
...
Driver.execute(Array("-tn", "SomeName", "-td", "SomePath"), () => new my_module)
...
}
}
object generator {
def main(args: Array[String]) = {
...
val a = generator(someopts)
a.exec
}
}
In this code flag -tn should change name of top-level circuit, but it changes only top-level filename. Top module names like "module generatormy_module", but i wants to generate name dynamically from params.
Is dat bug? Or how i can change a top-level module name?
PS: suggestName method doesn't works too!
The flag -tn is not intended to change the top-level circuit, only to specify it and use it as a default in filenames. The way to specify the name of a Chisel module is to override the desiredName method. You can override it with an argument to the Module constructor to make it more programmable. Modifying the above example:
class generator(options: Map[String, Any]) {
trait for_module extends abstractModule {
//generates trait with params
}
class my_module(name: String) extends abstractModule with for_module {
override def desiredName = name
}
def exec = {
val topName = "SomeName"
Driver.execute(Array("-tn", topName, "-td", "SomePath"), () => new my_module(topName))
...
}
}
object generator {
def main(args: Array[String]) = {
...
val a = generator(someopts)
a.exec
}
}
I am able to inject services into my Application class with no issues. But somehow I am unable to inject into the actors themselves.
My actor:
class PollerCrow #Inject()(
#Named("pollService") pollService: PollService[List[ChannelSftp#LsEntry]]
, #Named("redisStatusService") redisStatusService: StatusService
, #Named("dynamoDBStatusService") dynamoDbStatusService: StatusService
) extends BaseCrow {
... impl and stuff ...
}
My actor's companion object:
object PollerCrow extends NamedActor {
override def name: String = this.getClass.getSimpleName
val filesToProcess = ConfigFactory.load().getString("poller.crow.files.to.process")
def props = Props[PollerCrow]
}
I'm getting the following when I run it:
IllegalArgumentException: no matching constructor found on class watcher.crows.PollerCrow for arguments []
How can I fix this?
Edit:
I have binded my actors:
class ActorModule extends AbstractModule with AkkaGuiceSupport {
override def configure() {
bindPollerActors()
}
private def PollActors() = {
bindActor[PollerCrow](PollerCrow.name)
}
}
Edit 2:
Additional details to the class:
abstract class BaseCrow extends Crow with Actor with ActorLogging
class PollerCrow #Inject()(
#Named(ServiceNames.PollService) pollService: PollService[List[ChannelSftp#LsEntry]]
, #Named(ServiceNames.RedisStatusService) redisStatusService: StatusService
, #Named(ServiceNames.DynamoDbStatusService) dynamoDbStatusService: StatusService
) extends BaseCrow {
override def receive: Receive = {
...
}
}
object PollerCrow extends NamedActor {
override def name: String = this.getClass.getSimpleName
def props = Props[PollerCrow]
}
trait NamedActor {
def name: String
final def uniqueGeneratedName: String = name + Random.nextInt(10000)
}
You might to make Guice aware of you actors. This is clean approach:
import com.google.inject.AbstractModule
import play.api.libs.concurrent.AkkaGuiceSupport
class ActorModule extends AbstractModule with AkkaGuiceSupport {
override def configure(): Unit = {
bindActor[YourActor]("your-actor")
}
}
#Singleton
class YourActor #Inject()(yourService: IYourService) extends Actor {
override def receive: Receive = {
case msg => unhandled(msg)
}
}
And application.conf:
play.modules {
enabled += "ActorModule"
}
For those who don't want to hassle, just call injector directly and don't forget to import Application to scope:
Play.application.injector.instanceOf[YourService]
Play.application.injector.instanceOf(BindingKey(classOf[YourService]).qualifiedWith("your-name"));