How to mock an interface in Guice module with ScalaMock? - scala

How can I simply mock an interface needed for injection in Guice using ScalaMock?

I've ended up using
import org.scalamock.MockFactoryBase
import org.scalatest.exceptions.TestFailedException
trait MyMockFactory extends MockFactoryBase {
type ExpectationException = TestFailedException
override protected def newExpectationException(message: String, methodName: Option[Symbol]): TestFailedException = ???
}
and in TestModule
class TestModule extends AbstractModule with MyMockFactory {
override def configure(): Unit = {
val mockObject = mock[ClassName]
bind(classOf[ClassName]).toInstance(mockObject)
}
}

Use a separate test module by binding mocked instances to class names and use that module to inject objects for your tests.
Test Module goes like this:
class TestModule extends AbstractModule {
override def configure(): Unit = {
val mockObject = mock[ClassName]
bind(classOf[ClassName]).toInstance(mockObject)
}
}
Spec goes like this:
class SomeSpec extends FlatSpec {
val injector = Guice.createInjector(new TestModule)
val mockObject = injector.getInstance(classOf[ClassName])
}

Related

The easiest way to mock class with org.scalamock.scalatest.MockFactory

I have a trait:
trait MyRepository {
def save(dto: Dto): Unit
}
This trait is used by class:
class MyService(myRepository: MyRepository) {
def save(obj: Object): Unit = {
val dto = obj.toDto()
myRepository.save(dto)
}
}
and I want to test save method of MyService if it transform obj to dto properly. To do this I want to mock MyRepository.save(dto). This method should return it's args.
How to do this with org.scalamock.scalatest.MockFactory?
val mockRepo = mock[MyRepository]
(mockRepo.save _).expects(dto).returning(dto)
?

top level naming in chisel3

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
}
}

How to inject a trait with macwire

I have a Scala trait
trait UserRepository {
def findByEmail(email: String): User
}
I would like to inject this into a service with MacWire
class AccountService(){
val userRepo = wire[UserRepository]
}
And then use it in a test or class
class AccountServiceSpec {
val userRepo = new UserRepositoryImpl()
val accountSvc = new AccountService() //<--not manually injecting repo in service constructor
}
but I'm getting a compile error in the service class
Cannot find a public constructor nor a companion object for
accounts.repository.UserRepository
You may try to transform userRepo to class parameter, that allows macwire automatically provide its value for service:
import com.softwaremill.macwire._
case class User(email: String)
trait UserRepository {
def findByEmail(email: String): User
}
class AccountService(val userRepo: UserRepository)
class UserRepositoryImpl extends UserRepository{
def findByEmail(email: String): User = new User(email)
}
class AccountServiceSpec {
val userRepo = new UserRepositoryImpl()
val accountSvc = wire[AccountService] //<--not manually injecting repo in service constructor
}

Slick database configuration

I have an issue with Slick configuration in my Play application (Play 2.4.3).
I read documentation article but want to move dbConfig from controller to specified trait and mixin this trait to repository class.
There are several files in project: ClientRepository (class), BaseClientRepository (trait) and BaseDbRepository (trait).
trait BaseDbRepository {
val dbConfig = DatabaseConfigProvider.get[JdbcProfile](Play.current)
import dbConfig.driver.api._
def withConnection[T](f: => DBIOAction[T, NoStream, Nothing]) = {
dbConfig.db.run(f)
}
}
trait BaseClientRepository {
def getById(id: Int): Future[Client]
def getByLocation(location: String): Future[Seq[Client]]
}
class ClientRepository extends BaseDbRepository with BaseClientRepository {
def getById: Future[Client] = withConnection {
...
}
def getByLocation: Future[Seq[Client]] = withConnection {
...
}
}
This works great with my Client controller:
class Client extends Controller {
def getById(id: Int) = ???
}
But when I try to use DI with Guice:
class Client #Inject()(clientRepository: BaseClientRepository) extends Controller {
def getById(id: Int) = Action.async {
// I try to use client repository here
}
}
It failes with the following exception
CreationException: Unable to create injector, see the following errors:
1) An exception was caught and reported. Message: There is no started application
at com.google.inject.util.Modules$OverrideModule.configure(Modules.java:177)
I tried to move this definition val dbConfig = DatabaseConfigProvider.get[JdbcProfile](Play.current) into Global.scala and it just works, but as I now Global.scala is deprecated now.
So, where is the best place for it?
Update: I use injection module for DI configuration:
class InjectionModule extends AbstractModule {
def configure() {
bind(classOf[BaseClientRepository]).toInstance(new ClientRepository)
}
}
dbConfig should be a lazy val or a function in this case.
That works for me:
private lazy val dbConfig = DatabaseConfigProvider.get[JdbcProfile](Play.current)
Guice failed to inject an implementation of BaseClientRepository, the annotation #ImplementedBy can help.
#ImplementedBy(classOf[ClientRepository])
trait BaseClientRepository {
def getById(id: Int): Future[Client]
def getByLocation(location: String): Future[Seq[Client]]
}

How to inject services into actors using the Play 2.4?

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"));