How to provide scala object's with classes that have dependancy injection? - scala

I have a different car object's, one for example:
object Porsche extends Car with CarsUtilities {
override def start() {...}
override def canStart(fuelInLitr: Int) = fuelInLitr > 5
override val fuelInLitr = 45
override val carId = 1234567
}
this is how Car and CarsUtilities looks like:
trait Car {
def start(): Unit
val canStart(fuel: Double): Boolean
val fuelInLitr: Int
val carId: Int
}
trait CarsUtilities {
// method to prepare start() result
def prepareResult() = {...}
}
I have two api services:
class CarApiService (wsClient: WSClient, configuration: Configuration) {
def getCarkey(carId: String): Future[Option[CarKey]] = {
// here im performing api call using wsclient
}
}
and
class CarSupplierApiService #Inject()(configuration: Configuration) {
def getSupplierInfo(carId: String): Future[Option[SupplierInfo]] = // here im performing elastic search api call
}
Now, In some of the car object's, lets say 50% of them im gonna use those api services, sometime both and other times just one of them. What would be a best practice of providing those car objects those services instances?
I dont really want to use new to create an instance of them for each object that need to use them...so I thought maybe add them lazily to the CarsUtilities so all the car objects will have access to those api services when they need them...would that be a good solution?
also, if I do that how do I give then the Configuration and WSClient injections?
trait CarsUtilities {
lazy val carApiService = new CarApiService(???)
lazy val carSupplierApiService = new CarSupplierApiService(???)
// method to prepare start() result
def prepareResult() = {...}
}
thanks!!
using playframework 2.6, scala 2.11.8 :)

Generally, dependency injection and objects doesn't work together. Please see here for work-arounds, but in the long term you wan to get rid of objects that depend on injected classes.
What you probably need is some sort of business service that is a class an may be injected in controllers, like so:
class CarsUtilities #Inject() (carApiService: CarApiService, carSupplierApiService: CarSupplierApiService) {
// this class implements all the business logic and can use the services
def prepareResult() = {}
}
In the controllers, you may inject this CarsUtilities as well, because dependency injection "propagates".

Related

How do I mock a Scala Companion Object with EASYMOCK on Scala 3? [duplicate]

This question already has an answer here:
How to mock an Object in Scala
(1 answer)
Closed 7 months ago.
I have the following code...
class CoreDataSource {
def getConnection = {
println("Getting the connection")
CoreDataSource.getConnection
}
}
object CoreDataSource {
def getConnection: Option[Connection] = {
getDataSource.get.getConnection
}
def getDataSource: Option[DataSource] = {
...
config = new HikariConfig // This has side effects and can't run
...
val pool : DataSource = new HikariDataSource(config) // This has side effects and can't run
...
Some(pool)
}
}
I am trying to mock out the creation of the HikariDataSource and HikariConfig. I tried this...
class CoreDataSourceSpec extends AnyFunSpec with EasyMockSugar {
describe("Core Data Source") {
it("Do something") {
val cdsMock = mock[CoreDataSource.type]
...
}
}
}
But I get
Cannot subclass final class ....CoreDataSource$
What is the proper way to Mock out a companion object using EasyMock
You don't.
Companion object should only perform pure computations (at least don't contain state) which don't require mocking. Most of the time it's purpose is to store factories and instances of type classes (implicits/givens) for your type.
If you store a mutable state (e.g. connection to the database) in companion you messed up. If you have a Java background, think this way: would you mock static methods of a class? (If you're drifting towards PowerMockito you should reconsider your life choices).
Your example shows that you want to store the connection somewhere - storing it in companion is basically global, shared, mutable state which is universally a bad idea, no matter the background.
Create factory of CoreDataSource in its companion, then pass around CoreDataSource instance directly. No issue with mocking that in your tests.
class CoreDataSource(dataSource: DataSource) {
def getConnection: Connection =
dataSource.getConnection
}
object CoreDataSource {
def createHikari(config: HikariConfig): CoreDataSource =
new CoreDataSource(new HikariDataSource(config))
}
// in test:
val dataSource = mock[DataSource]
val coreDataSource = new CoreDataSource(dataSource)
// then mock dataSource.getConnection
Doing it another way requires solving the hard problem that you have 0 reasons to have in the first place. If this companion object is not your but someone else and you cannot rewrite it - wrap it in your own code that you can control and mock easily.
EDIT. In case you are using something like Google Cloud... it still doesn't make sense to store everything in companion and mock it.
// functionality
class MyService(
connection: Connection
) {
def someFunctionality(arg: Arg): Result = ...
}
// in test
// given
val connection = mock[Connection] // mocking DB sounds like a bad idea but whatever
val myService = new MyService(connection)
// when
myService.someFunctionality(arg)
// then
// assertions
// adapter for Google Cloud, other cloud solutions should be similar
class MyFunction extends HttpFunction {
private val config = ...
private val coreDataSource = CoreDataSource.hikari(config)
private val connection = coreDataSource.getConnection
private val myService = new MyService(connection)
override def service(request: HttpRequest, response: HttpResponse): Unit = {
// extract data from request, then
val result = myService.someFunctionality(arg)
// then send result in response
}
}
And if you needed to cache these private vals - what you are caching is NOT related to business logic at all, it merely wires things together, like main in Java which is never tested, nor require testing.
So you could implement it like:
class MyFunction extends HttpFunction {
override def service(request: HttpRequest, response: HttpResponse): Unit = {
// extract data from request, then
val result = MyFunction.myService.someFunctionality(arg)
// then send result in response
}
}
object MyFunction {
// dependency injection and initialization
private val config = ...
private val coreDataSource = CoreDataSource.hikari(config)
private val connection = coreDataSource.getConnection
val myService = new MyService(connection)
}
where wrapper MyFunction is NOT tested, but MyService which does all the job is easily testable.
You should definitely read more about the language, beside the fact that the other answer mentioned (which is you should only contain pure class-level functionalities in the companion object), you cannot do it. Why? Because companion objects are singleton objects of a final class, which can access private states of the companion class itself and vice versa (think of it kind of like static data of the class).
The thing is, companion object actually is an object of a final class (which if you want, I can provide more details about them). Final classes cannot be mocked, simply because they are "final", and their behavior cannot be changed (even by its subclasses). And mocking is all about mocking a class behavior, not an object's behavior.

How would you wrap a class containing a concurrenthash map with cats?

Say I have a class that contains an inner concurent hash map
final class SomeClass() {
private val byUserId = new ConcurrentHashMap[User.ID, Vector[User]](64)
// ...
}
Now if I wanted to have this class referenced in my API endpoints and other areas in my services, how would I wrap this in a cats IO/effects?
Since this is already management state, would it still be an effects IO?
Need some guidance on this as I am a little confused and newish to FP.
I guess it depends on how you are going to use it. Here are my thoughts on this.
So you probably want one instance of this class (and one map) shared between different processes, right? So the instantiation of it should be wrapped in IO. Then you can inject it as a dependency in all other places where you need to use it. Then all the public methods of this class that have anything to do with the Map should return an IO as well.
final class SomeClass private() {
private val byUserId = new ConcurrentHashMap[User.ID, Vector[User]](64)
def getById(id: User.ID): IO[Vector[User]] = ???
def setUser(id: User.ID, user: Vector[User]): IO[Unit] = ???
}
object SomeClass {
def apply() = IO(new SomeClass())
}
SomeClass().flatMap { instance =>
// do stuff with it
Api(instance)
}

Injecting playFramework dependancies to scala object using MacWire traits fail

Lets say I have bunch of car objects in my project, for example:
object Porsche extends Car {
override def start() {...}
override def canStart(fuelInLitr: Int) = fuelInLitr > 5
override val fuelInLitr = 45
override val carId = 1234567
}
im extending Car which is just a trait to set a car structure:
trait Car {
def start(): Unit
val canStart(fuel: Double): Boolean
val fuelInLitr: Int
val carId: Int
}
Now, in the start() method I want to use some api service that will give me a car key based on its id so I cant start the car.
So I have this CarApiService:
class CarApiService (wsClient: WSClient, configuration: Configuration) {
implicit val formats: Formats = DefaultFormats
def getCarkey(carId: String): Future[Option[CarKey]] = {
val carInfoServiceApi = s"${configuration.get[String]("carsdb.carsInfo")}?carId=$carId"
wsClient.url(carInfoServiceApi).withHttpHeaders(("Content-Type", "application/json")).get.map { response =>
response.status match {
case Status.OK => Some(parse(response.body).extract[CarKey])
case Status.NO_CONTENT => None
case _ => throw new Exception(s"carsdb failed to perform operation with status: ${response.status}, and body: ${response.body}")
}
}
}
}
I want to have the ability to use getCarkey() in my car objects, so I created a CarsApiServicesModule which will give my access to the carApiService and I can use its methods:
trait CarsApiServicesModule {
/// this supply the carApiService its confuguration dependancy
lazy val configuration: Config = ConfigFactory.load()
lazy val conf: Configuration = wire[Configuration]
/// this supply the carApiService its WSClient dependancy
lazy val wsc: WSClient = wire[WSClient]
lazy val carApiService: CarApiService = wire[CarApiService]
}
and now I want to add mix this trait in my car object this way:
object Porsche extends Car with CarsApiServicesModule {
// here I want to use myApiService
// for example: carApiService.getCarkey(carId)...
}
but when compiling this I get this error:
does anyone know what is the issue?
also, is that design make sense?
You need to keep in mind that wire is just a helper macro which tries to generate new instance creation code: it's quite dumb, in fact. Here, it would try to create a new instance of WSClient.
However, not all objects can be instantiated using a simple new call - sometimes you need to invoke "factory" method.
In this case, if you take a look at the readme on GitHub, you'll see that to instantiate the WSClient, you need to create it through the StandaloneAhcWSClient() object.
So in this case, wire won't help you - you'll need to simply write the initialisation code by hand. Luckily it's not too large.

How to setup my mock Dao classes when using Guice?

A typical service looks like this:
trait BaseService extends LazyLogging {
def getDb() = {
DatabaseHelper.getDb // database for the scala slick library
}
}
abstract class UserService extends BaseService {
def getById(userId: Int): Option[User]
}
class UserServiceImpl #Inject(val userDao: UserDao) extends UserService = {
def getById(userId: Int): Option[User] = {
getDb().withSession { implicit session =>
return userDao.getById(userId)
}
}
}
Using Guice I wire up my objects like:
class ServiceModule extends ScalaModule {
def configure() {
bind[UserDao].to[UserDaoImpl]
bind[UserService].to[UserServiceImpl]
}
}
Now when I am unit testing using scalatest, I am a bit confused how I can de-couple the database access since I want to mock the database responses.
My spec looks like:
class UserServiceSpec extends UnitSpec with MockitoSugar {
val userService = injector.getInstance(classOf[UserService])
describe("UserServiceSpec") {
it("should do someting") {
val abc = userService.doSomething();
abc.name should be("abc")
}
}
}
My UnitSpec class wires up my Guice.
I am confused, where should I create the mock objects (using mockito) and how should I wire them using Guice? In the ServiceModule or?
My design seems wrong since my BaseService has a connection to the database, I need to refactor that out somehow.
Looking for a way to get out of this bad design I currently seem to have, ideas?
You can move the db connection to DAO layer. Your application should have three layers: controller -> service -> DAO. All the service layer needs to know is functionalities provided by DAO, i.e. CRUD operations; it should not know anything about db connection since that is DAO's responsibility.
I am not really sure about Slick framework, but for Play framework with Guice, it allows to disable "real" bindings (injected dependencies) that you expect when the application is running and enable bindings that are only for testing like this:
implicit override lazy val app = new GuiceApplicationBuilder()
.configure(appConfig)
.disable(classOf[ReactiveMongoModule], classOf[CommonModule])
.bindings(bind(classOf[ReactiveMongoApi]).toInstance(api))
.bindings(TestDaoModule())
.build()
This is a complete integration test (controller layer), hope that it helps: https://github.com/luongbalinh/play-mongo/blob/master/test/controllers/UserControllerTest.scala

Abstract fields for dependency injection

In Scala, is there there anything wrong with using the below method of dependency injection.
// Define an interface
trait FileStorage {
def readFile(filename:String):OutputStream
}
// And an implementation
class S3FileStorage extends FileStorage {
def readFile(filename:String):OutputStream = ???
}
// Define our service as a trait with abstract fields that need to be
// injected in order to construct. All implementation details go here.
trait FileHTTPServer {
val fileStorage:FileStorage
def fetchFile( session:Session, filename:String ) = ???
}
Now we wire things up
// Wire up a concrete file service that we actually use in code
// No implementation details should go here, we're simply wiring up a FileHttpServerl
// An entire project could be wired up this way in a central location if desired.
object S3FileHttpServer extends FileHTTPServer {
val fileStorage = new S3FileStorage
}
// We could also do this anonymously
val myHttpServer = new FileHttpServer {
val fileStorage = new S3FileStorage
}
// Or create a mocked version for testing
val mockedHttpServer = new FileHttpServer {
val fileStorage = mock[FileStorage]
}
Obviously the Cake pattern provides more flexibility (particularly around self-types), however for simpler use cases this has much less boilerplate, while still providing compile time checking and a clean unambiguous interface.
Yes, this is absolutely fine approach. And yes, sometimes you can use constructor injection, nothing wrong with that too. But with constructor injection you have to propagate your dependencies manually, while with cake pattern your dependencies are propagated automatically via self-type annotations. So for big projects constructor injection actually lead to more boilerplate than cake pattern, especially at the construction site (where you create all your objects and set up dependencies between them).
However, what you have presented is not full-fledged cake pattern. In real cake pattern there is an additional layer around business logic classes, so-called components, and you do not wire up logic classes directly but components instead.
trait FileStorageComponent {
def fileStorage: FileStorage
trait FileStorage {
def readFile(filename: String): OutputStream
}
}
trait S3FileStorageComponent extends FileStorageComponent {
val fileStorage = new S3FileStorage
class S3FileStorage extends FileStorage {
def readFile(filename: String): OutputStream = ???
}
}
trait FileHttpServerComponent {
self: FileStorageComponent =>
val fileHttpServer = new FileHttpServer
class FileHttpServer {
def fetchFile(session: Session, filename: String) = ???
}
}
// Wiring
object S3FileHttpServer extends FileHttpServerComponent with S3FileStorageComponent
// Anonymous
val server = new FileHttpServerComponent with S3FileStorageComponent
// Mocking
object TestFileHttpServer extends FileHttpServerComponent with FileStorageComponent {
val fileStorage = mock[FileStorage]
}
In this approach there are more boilerplate in traits definitions, but in return you have greater flexibility and very clear dependency management on the use place. For example, here is how program entry point in one of my projects looks like:
object Main
extends MainUI
with DefaultActorsManagerComponent
with DefaultPreferencesAccessComponent
with DefaultModelComponent
with DefaultMainWindowViewComponent
with DefaultMainWindowControllerComponent
with MainWindowReporterComponent
with DefaultClientActorComponent
with DefaultResponseParserActorComponent
with DefaultArchiverActorComponent
with DefaultMainWindowAccessActorComponent
with DefaultUrlParserComponent
with DefaultListenerActorComponent
with DefaultXmlPrettifierComponent
All main program components are in one place. Pretty neat IMO.