How to inject a trait with macwire - scala

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
}

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)
?

How to mock an interface in Guice module with ScalaMock?

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

DI in Scala with Cake Pattern

This article explains Dependency Injection via Scala's Cake Pattern.
My understanding of this pattern's benefit is that traits can be mixed in (production v. test) with static checking.
In Mr. Bonér's example, he lists this finished (per example) code:
UserRepositoryComponent and UserServiceComponent
I added comments per my understanding.
trait UserRepositoryComponent {
val userRepository: UserRepository // stand-alone component
class UserRepository {
... // actual implementation here
}
}
trait UserServiceComponent {
this: UserRepositoryComponent => //Requires a mixed-in UserRepo*Component
val userService: UserService
class UserService {
... // actual implementation here
}
}
My understanding is that the Service depends on injection of a Repository component.
For production purposes, the following can be used to wire a "production" Repository component into the UserServiceComponent:
object ComponentRegistry extends
UserServiceComponent with
UserRepositoryComponent
{
val userRepository = new UserRepository
val userService = new UserService
}
If our production code wanted to use the userRepository or userService, is the correct way to use them via a simple import?
I think that I understand half of the article up to this point, but I'm not sure how to use the ComponentRegistry object.
You're running head first into the bakery of doom bro:
What are some compelling use cases for dependent method types?
To answer your question, the proper way to use userService would be to use another trait and cake it up:
trait Example { this: UserServiceComponent =>
def getExampleUser() = userService.getUser("ExampleUser")
}
Now whatever this new trait does isn't directly coupled to anything like the object ComponentRegistry. Instead your application becomes this:
object Application extends
Example with
UserServiceComponent with
UserRepositoryComponent
{
val userRepository = new UserRepository
val userService = new UserService
}
Anyway, you should run for the hills because if you really want to use cake you should be doing something more like this:
trait UserRepositoryComponent {
type UserRepository <: UserRepositoryLike
val userRepository: UserRepository
trait UserRepositoryLike {
def getUserOrSomething()
}
}
trait UserRepositoryComponentImpl extends UserRepositoryComponent {
type UserRepository = UserRepositoryImpl
val userRepository = new UserRepositoryImpl
class UserRepositoryImpl extends UserRepositoryLike {
override def getUserOrSomething() = ???
}
}
trait UserServiceComponent {
this: UserRepositoryComponent =>
type UserService <: UserServiceLike
val userService: UserService
trait UserServiceLike {
def getUserNameById(id: Int): String
}
}
trait UserServiceComponentImpl extends UserServiceComponent {
this: UserRepositoryComponent =>
type UserService = UserServiceImpl
val userService = new UserServiceImpl
class UserServiceImpl extends UserServiceLike {
override def getUserNameById(id: Int) = userRepository.getUserOrSomething
}
}
trait Example {
this: UserServiceComponent =>
def getExampleUser() = userService.getUserNameById(1)
}
object Application extends
Example with
UserRepositoryComponentImpl with
UserServiceComponentImpl
Now save yourself some time, drop the cake pattern, and do something simple.

Replace only repositories on a global cake pattern application

I'm trying to use the cake pattern for the first time.
I kind of understand how it works, but would like to know if it is possible to mix already mixed traits or something like that.
What I would like is to build a global application with the cake pattern.
And I want another version of that application which would be the same, except at the repository level.
Is it possible to do something like:
trait application extends DefaultUserServiceComponent with MongoUserRepositoryComponent
object realApplication extends application
object fakeApplication extends FakeUserRepositoryComponent with application
I mean: reusing the already built application, when building a fake application using fake repositories?
Short answer: No. You would be inheriting conflicting members. See the following code snippet:
trait Repository {def authenticate(username: String, password: String): String}
trait UserServiceComponent {self: UserRepositoryComponent =>
val userService: UserService = new UserService
class UserService {
def authenticate(username: String, password: String): String =
repository.authenticate(username, password)
}
}
trait UserRepositoryComponent {
def repository: Repository
}
trait MongoUserRepositoryComponent extends UserRepositoryComponent {
val repository: Repository =
new Repository {def authenticate(username: String, password: String) = "MongoAuthed"}
}
trait MockUserRepositoryComponent extends UserRepositoryComponent {
val repository: Repository =
new Repository {def authenticate(username: String, password: String) = "MockAuthed"}
}
trait Application extends UserServiceComponent with MongoUserRepositoryComponent
object RealApplication extends Application
// The following will be an error: "object FakeApplication inherits conflicting members:"
object FakeApplication extends Application with MockUserRepositoryComponent
Instead, to have the desired behavior, define Application as such:
trait Application extends UserServiceComponent {self: UserRepositoryComponent =>}
object RealApplication extends Application with MongoUserRepositoryComponent
object FakeApplication extends Application with MockUserRepositoryComponent
To keep the hierarchy given in the OP, you would need to modify the code as such:
trait MongoUserRepositoryComponent extends UserRepositoryComponent {
private val _repository = new Repository {def authenticate(username: String, password: String) = "MongoAuthed"}
def repository: Repository = _repository
}
trait MockUserRepositoryComponent extends UserRepositoryComponent {
private val _repository = new Repository {def authenticate(username: String, password: String) = "MockAuthed"}
def repository: Repository = _repository
}
trait Application extends UserServiceComponent with MongoUserRepositoryComponent
object RealApplication extends Application
object FakeApplication extends Application with MockUserRepositoryComponent {
override val repository: Repository = super[MockUserRepositoryComponent].repository
}
The additional private val _repository's are necessary so that we can define repository as a function, so that it can be used as an override in FakeApplication. (Using super[type] to override only works with functions).
EDIT: In the end, the purpose of the cake pattern is to develop a hierarchy where one does not need to override as in the last code snippet I provided. In reality, the trait Application should not exist at all, only RealApplication and FakeApplication. (In the 2nd code snippet I'm essentially doing nothing more than renaming UserServiceComponent to Application).

Can the Cake Pattern be used for non-singleton style dependencies?

Most of the examples of the Cake Pattern I've come across appear to consider dependencies as singleton type services; where there is only one instance of each type in the final assembly of components. Is it possible to write a configuration that has more than one instance of a particular type, perhaps configured in different ways, when using the Cake Pattern for dependency injection?
Consider the following components. Generic HTTP service:
trait HttpService { def get(query:String):String }
trait HttpServiceComponent {
val httpService:HttpService
class HttpServiceImpl(address:String) extends HttpService {
def get(query:String):String = ...
}
}
Trade & Company services, that each depend on an HttpService, which may be different instances:
trait TradeService { def lastTrade(symbol:String):String }
trait TradeServiceComponent {
this:HttpServiceComponent => // Depends on HttpService
val tradeService:TradeService
class TradeServiceImpl extends TradeService {
def lastTrade(symbol:String):String =
httpService.get("symbol=" + symbol)
}
}
trait CompanyService { def getCompanySymbols(exchange:String):String }
trait CompanyServiceComponent {
this:HttpServiceComponent => // Depends on different HttpService instance
val companyService:CompanyService
class CompanyServiceImpl extends CompanyService {
def getCompanySymbols(exchange:String):String =
httpService.get("exchange=" + exchange)
}
}
Main app component that depends on Trade & Company services:
trait App { def run(exchange:String):Unit }
trait AppComponent {
this:CompanyServiceComponent with TradeServiceComponent =>
val app:App
class AppImpl extends App {
def run(exchange:String) =
companyService.getCompanySymbols(exchange).split(",").foreach(sym => {
val lastTrade = tradeService.lastTrade(sym)
printf("Last trade for %s: %s".format(sym, lastTrade))
})
}
}
Is it possible to wire up the App so that its TradeService uses a HttpService that points to one address, and its CompanySerivce uses a different HttpService instance pointing to another address?
As you can see from the answers (notably Daniel's, but also your own), it is possible, but it doesn't look elegant. The difficulty appears because when you use the Cake pattern, you mix all required traits into one object (using "with" keyword), and you cannot mix a trait more than once into one instance. That is how mixins work, and the Cake is based on them.
The fact you can force Cake to handle non-singleton dependencies doesn't mean you should do it. I would advise you to simply use plain-old constructor in such cases, that is where self-type annotation doesn't fit well:
trait HttpService { ... }
/* HttpServiceImpl has become a top-level class now,
* as the Cake pattern adds no more value here.
* In addition, trait HttpServiceComponent gets deleted */
class HttpServiceImpl(address:String) extends HttpService {
...
}
trait TradeService { def lastTrade(symbol:String):String }
trait TradeServiceComponent {
// The dependency on HttpService is no longer declared as self-type
val tradeService:TradeService
// It is declared as a constructor parameter now
class TradeServiceImpl(httpService: HttpService) extends TradeService {
def lastTrade(symbol:String):String =
httpService.get("symbol=" + symbol)
}
}
trait CompanyService { def getCompanySymbols(exchange:String):String }
trait CompanyServiceComponent {
// Again, self-type annotation deleted
val companyService:CompanyService
// Again, the dependency is declared as a constructor parameter
class CompanyServiceImpl(httpService: HttpService) extends CompanyService {
def getCompanySymbols(exchange:String):String =
httpService.get("exchange=" + exchange)
}
}
The App and AppComponent traits stay in their original form. Now you can use the all components in the following way:
object App {
def main(args:Array[String]):Unit = {
val appAssembly = new AppComponent
with TradeServiceComponent
with CompanyServiceComponent {
// Note, that HttpServiceComponent it neither needed nor mixed-in now
val tradeService = new TradeServiceImpl(
new HttpServiceImpl("http://trades-r-us.com"))
val companyService = new CompanyServiceImpl(
new HttpServiceImpl("http://exchange-services.com"))
val app = new AppImpl
}
appAssembly.app.run(args(0))
}
}
Also, you may want do double-check if the Cake pattern is really best suited for your needs, as it is actually a complex pattern and dependency injection is only one part of it. If you use it only for DI, I would advise you to use a simpler solution. I've blogged about that here.
Since each "client" may need a different implementation, you could just parameterize the service.
trait HttpService { def get(query:String):String }
trait HttpServiceComponent {
def httpService(name: String):HttpService
class HttpServiceImpl(address:String) extends HttpService {
def get(query:String):String = ...
}
}
To be used like this:
trait TradeService { def lastTrade(symbol:String):String }
trait TradeServiceComponent {
this:HttpServiceComponent => // Depends on HttpService
val tradeService:TradeService
class TradeServiceImpl extends TradeService {
def lastTrade(symbol:String):String =
httpService("TradeService").get("symbol=" + symbol)
}
}
The final mix would then do something like this:
trait AppComponent {
this:CompanyServiceComponent with TradeServiceComponent =>
val httpServices = Map( "TradeService" -> new HttpServiceImpl("http://trades-r-us.com"),
"CompanyService" -> new HttpServiceImpl("http://exchange-services.com"))
def httpService(name: String) = httpServices(name)
This compiles and runs as expected, but it leaves a lot to be desired:
object App {
def main(args:Array[String]):Unit = {
val tradeServiceAssembly = new TradeServiceComponent with HttpServiceComponent {
val httpService = new HttpServiceImpl("http://trades-r-us.com")
val tradeService = new TradeServiceImpl
}
val companyServiceAssembly = new CompanyServiceComponent with HttpServiceComponent {
val httpService = new HttpServiceImpl("http://exchange-services.com")
val companyService = new CompanyServiceImpl
}
val appAssembly = new AppComponent
with TradeServiceComponent
with CompanyServiceComponent
with HttpServiceComponent {
lazy val httpService = error("Required for compilation but not used")
val tradeService = tradeServiceAssembly.tradeService
val companyService = companyServiceAssembly.companyService
val app = new AppImpl
}
appAssembly.app.run(args(0))
}
}