fixture.FeatureSpec / withFixture(OneArgTest) issue - scala

I want to share a Database / Knowledge base, for a suite of test. I want it to be available for any test suite. I am using featureSpec
Following the Documentation, I use fixture.FeatureSpec.
As of now i have defined the following:
trait InteractionKbFixtureTrait { this: fixture.Suite =>
type FixtureParam = InteractionKB
def withFixture(test: OneArgTest): Unit = {
val kb = KbFactory.createKb("", "") // create the fixture
try {
this.withFixture(test.toNoArgTest(kb)) // "loan" the fixture to the test
} finally {
//kb.stop() // clean up the fixture
}
}
}
followed by
class ExampleSpec extends fixture.FeatureSpec with InteractionKbFixtureTrait {
}
I get the following error :
Type overriding method withFixture in trait Suite of type (test: ExampleSpec.this.OneArgTest) org.scalatest.Outcome;
method withFixture in trait InteractionKbFixtureTrait of type (test: ExampleSpec.this.OneArgTest) Unit has incompatible type InteractionKbFixtureTrait.scala
Any help ?

Method def withFixture should return type org.scalatest.Outcome, whereas your def withFixture is returning Unit. Error message is saying that quite clearly.
So for fixing it you need to change line:
def withFixture(test: OneArgTest): Unit = {
like so:
def withFixture(test: OneArgTest): org.scalatest.Outcome = {

Related

what is the best practice of implementing a factory pattern/method in scala?

I wonder what is the best practice of implementing a factory pattern/method in scala?
say we have those kind of objects:
case class foo1(a:Int,b:String)
case class goo1(z:Double, w:String)
how to create them in generic way [by maybe using a trait etc...]?
thanks
If your goal is to write your own dependency injection module that provides instances on the fly, I'd strongly suggest that you lookup some of the existing tools. A simple google search for "Scala dependency injection frameworks" will yield many result such as MacWire, Guice,ReaderMonad,cake pattern and etc.
However my judgement aside from your motive and to simply answer the question here's one way you would do this in scala that also is type safe:
trait FactoryMethod[T] {
type Args
def defaultArgs: Args
def withArgs(args: Args): T
def default: T = withArgs(defaultArgs)
}
case class Foo(a:Int,b:String)
object Foo {
implicit object factory extends FactoryMethod[Foo] {
override type Args = (Int,String)
override def withArgs(args: Args): Foo = (Foo.apply _).tupled(args)
override def defaultArgs: Args = (1,"foo")
}
}
case class Goo(z:Double, w:String)
object Goo {
implicit object factory extends FactoryMethod[Goo] {
override type Args = (Double,String)
override def withArgs(args: Args): Goo = (Goo.apply _).tupled(args)
override def defaultArgs: Args = (2L,"goo")
}
}
object Factory {
def of[T](implicit factory: FactoryMethod[T]): factory.Args => T = factory.withArgs
def instanceOf[T](implicit factory: FactoryMethod[T]): T = factory.default
}
//obtain instance with default arguments
Factory.instanceOf[Goo]
//type safe way of obtaining instance with custom fed arguments
Factory.of[Foo].apply((-22,"baz"))
//By type safe I mean that the line below won't compile because the
//arguments fed for Foo are not compatible:
//Factory.of[Foo].apply(("bar","baz"))
//Note that if you abstract over the types Goo and Foo like this:
//def myMethod[T]: T = {
// Factory.instanceOf[T]
//}
//It won't compile unless you also ask for the needed implicit
//on the method signature
def myMethod[T: FactoryMethod]: T = {
Factory.instanceOf[T]
}

How to build a wrapper around scalatest's "it" keyword?

I am attempting to build a wrapper around scalatest's it keyword. However, this solution does not seem to work as intended. Moreover, it does not even compile:
trait MyFunSpec extends FunSpec {
private val _it: FunSpec.this.ItWord = it
protected def it(specText: String, testTags: org.scalatest.Tag*)
// ...do something extra here...
(testFun: => Any /* Assertion */)(implicit pos: Position): Unit = {
_it(specText, testTags: _*)(testFun)(pos)
// ...do something extra here...
}
}
The error message I am getting after compiling this code is as follows:
[error] MyFunSpec.scala: ambiguous reference to overloaded definition,
[error] both method it in trait MyFunSpec of type (specText: String, testTags:
org.scalatest.Tag*)(testFun: => Any)(implicit pos:
org.scalactic.source.Position)Unit
[error] and value it in trait FunSpecLike of type => FunSpecSpec.this.ItWord
[error] match argument types (String)
Please note the main idea is that method's name remains it, so renaming it to something like alternativeIt is not a satisfactory solution here.
Any suggestions, what am I doing wrong here? Any solution would be highly appreciated! Thanks!
Try this:
trait MyFunSpec extends FunSpec {
override protected val it = new ItWord {
override def apply(specText: String,testTags: org.scalatest.Tag*)(testFun: => Any)(implicit pos: org.scalactic.source.Position): Unit = {
println("Before")
super.apply(specText, testTags:_*)(testFun)(pos)
println("After")
}
}
}

How do I share a single object with multiple Scalatest suites?

I have a number of test files, each with their own tests. Until now, each one has a trait in which I create a configuration object.
Building that object now takes the better part of two minutes, as it has to do a lot of work calling a number of databases (don't ask - really, it has to be done).
Is there a way to share this object (tldConfigMap, below) between multiple test suites in multiple files without having to build it over and over?
Here's how I was doing it - as you can see, when brought in as a trait, load() will be called every time:
trait TLDMapAcceptanceIsLoadedSpec extends org.scalatest.fixture.FlatSpecLike with TLDConfigMap {
val tldConfigMap: Map[String, TLDConfig] = load(withAttributes = true).right.get
type FixtureParam = Map[String, TLDConfig]
def withFixture(test: OneArgTest) = {
withFixture(test.toNoArgTest(tldConfigMap)) // "loan" the fixture to the test
}
}
You could just put it into an object (assuming it's really config and isn't changed by tests):
object TldConfigMap {
val tldConfigMap: Map[String, TLDConfig] = load(withAttributes = true).right.get
}
trait TLDMapAcceptanceIsLoadedSpec extends org.scalatest.fixture.FlatSpecLike with TLDConfigMap {
def tldConfigMap: Map[String, TLDConfig] = TldConfigMap.tldConfigMap // or just use it directly
type FixtureParam = Map[String, TLDConfig]
def withFixture(test: OneArgTest) = {
withFixture(test.toNoArgTest(tldConfigMap)) // "loan" the fixture to the test
}
}

Understanding implicit conversions

I'm reading Scala documentation of implicit conversions and decided to try it out:
object Main extends App {
val test = TestConversion(100)
test.its
}
class Test[T](val t : T) {
def its = println(t)
}
object Test {
def apply[T](t: T): Test[T] = new Test(t)
}
class TestConversion(v : Int) {
val value = v
}
object TestConversion{
implicit def implicitConversionTest2Int(ict : TestConversion): Test[Int] = Test(ict.value)
def apply(v : Int) = new TestConversion(v)
}
As it's said:
To define your own implicit conversions, you must first import
scala.language.implicitConversions (or invoke the compiler with
-language:implicitConversions). The feature must be explicitly enabled because it has pitfalls if used indiscriminately.
I tried it both in IntelliJ and online IdeOne and I didn't add anything special to make it compile.
What pitfalls it brings and why does it work without any imports?
You don't need to import anything.
The idea is that you can declare implicit conversion function wherever you want in the scope.
For example:
case class Coins(amount:Int)
case class Bills(amount:Int)
object Main {
implicit def billsToCoins(bills:Bills):Coins = Coins(bills.amount * 100)
def printCoins(coins:Coins) = println(s"You have ${coins.amount} coins." )
def main(args:Array[String]): Unit ={
printCoins(Bills(3))
}
}
I have declared here implicit function billsToCoins so it is available in scope of the main function. The only thing needed for the function to act as implicit converter is to have the implicit modifier, compiler will find it and use. You see that the printCoins function takes argument of the Coins type but I was able to pass the value of Bills type and it was successfully created.
Here is the console output:
You have 300 coins.
Process finished with exit code 0

Inject a dependency inside an object

I'm new to the Play framework and scala and I'm trying to inject a dependency inside a companion object.
I have a simple case class, like:
case class Bar(foo: Int) {}
With a companion object like:
object Bar {
val myDependency =
if (isTest) {
// Mock
}
else
{
// Actual implementation
}
val form = Form(mapping(
"foo" -> number(0, 100).verifying(foo => myDependency.validate(foo)),
)(Bar.apply)(Bar.unapply))
}
This works fine, but it's not really a clean way to do it. I'd like to be able to inject the dependency at build time so that I can inject different mock objects when testing and different real implementations in development and production.
What's the best way to achieve this?
Any help really appreciated. Thanks!
Along the lines of the Cake, we can try to change your example to
trait Validator {
def validate(foo: Int): Boolean
}
trait TestValidation {
val validator = new Validator {
def validate(foo: Int): Boolean = ...
}
}
trait ImplValidation {
val validator = new Validator {
def validate(foo: Int): Boolean = ...
}
}
trait BarBehavior {
def validator: Validator
val form = Form(mapping(...))(Bar.apply)(Bar.unapply)
}
//use this in your tests
object TestBar extends BarBehavior with TestValidation
//use this in production
object ImplBar extends BarBehavior with ImplValidation
You should additionally try and test if this example fits well within the Play Framework, too