I have a class. It has a companion object A with a factory method.
class A private[somepackage](x: Int) {
}
object A {
def createA(y: Int): A = {
new A(y)
}
}
Now I need to create the mock object of A in a scalatest file which is in a different package.
When I give
private val a = mock[A] --> I get compilation error.
constructor A in class A cannot be accessed in <<somewhere>>.
Is there a better way to mock the object ??
In your test sources, create a test double in the same package:
package somepackage
class MockableA extends A(0)
then just create a mock[MockableA] in your tests and continue as usual.
But the answer with a proxy/facade should work too if you are willing to change production sources to facilitate tests.
Consider using a proxy to access class A, and stub/mock that proxy class instead.
E.g., if A.doStuff is what you want to mock/stub, and A.accessStuff is what you need in your code, create a class
class ADecorated(underlying: A) {
def doStuff() {
underlying.doStuff()
// whatever I want to do
}
def accessStuff() {
x = underlying.accessStuff()
// do something else and return
}
// Any other method you want to use
}
Replace usage of A.createA with new ADecorated(A.createA()). ADecorated is what you work with now
Related
I'm using scalatest and when I test my code, I want to replace an implementation of a function to return something else when running tests.
In JavaScript its really simple and I thought I could do the same in scala.
So what I want is something like this:
object Module {
private def bar(): Int = {
5
}
def foo(): Unit = {
println(bar())
}
}
And the test will be something like that (dont mind the syntax, you get the idea)
class Test extends FunSpec {
mock(Module.bar, () => 1)
describe("Test") {
it("Test") {
Module.foo() // will print 1
}
}
}
I have searched the internet and came across scala mock libraries but none of them seemed to be able to replace the implementation of a method.
In every library you have to defined your mock in the test and pass it on to the code, but I don't want to do that.
Is there anyway to achieve this?
Thank you.
You can't mock Object in Scala, because it's like a static class in java (which you can't mock either). (and you can't mock scala objects not in mockito nor scalamock (maybe in their next version)).
But, if you change your object Module to class Module, you can mock this function easily (using mockito):
val mockModule = mock[Module]
when(mockModule.bar()).thenReturn(1)
You can do a fake class that has that function and put the value you want, if you dont want to use mocks, like this:
trait SMT{
def bar: Int
}
class RealImpl extends SMT{
def bar: Int = 5
}
class FakeImpl extends SMT{
def bar: Int = 1
}
I am trying to inject ehcache via the Play Framework. I am injecting it into a companion class, but that class is being instantiated in an abstract class elsewhere as well as the companion object. I do not want to inject anything into the abstract class because it is being used elsewhere.
For example, this is basically how the companion class and object are set up (removed some logic and extensions for better readability):
class Setting #Inject()(cached: DefaultSyncCacheApi) {
def isCached(id:String): Boolean = {
val cachedItem = cached.get(id)
cachedItem.isDefined
}
}
object Setting {
def getId(id:String): Setting = {
val setting = new Setting //I know this doesn't work
if (setting.isCached(id)) {
//retrieval logic
}
setting
}
}
This is the abstract class where it is being instantiated:
abstract class UsingSettingAbstract {
def methodUsingSetting(): String = {
val setting = new Setting
val str = new String
//logic in here
str
}
}
I have tried to create an empty constructor in the Setting class with def this() { }, and creating a chain of constructors, but have so far been unsuccessful in getting the cache to be successfully injected.
I did different versions of below, initializing the cache variable with cached or trying to pass through cached:
class Setting #Inject()(cached: DefaultSyncCacheApi) {
val cache:DefaultSyncCacheApi
def this() {
this(cache)
}
}
Is there a way to get DI to work with this setup, or would something like a factory pattern work better?
With guice you can pass any created instance to the injectors "requestInjection()" method. This will trigger method and field injection on that instance.
So as long as you have access to the injector, you can get injections done.
I have a doubt related to dependency injection using Google Guice.
I have a trait which has few implemented methods
trait ATrait {
def someMethodA(parameters: ArgType) = {
//code
}
def someMethodB(parameters: ArgType) = {
//code
}
}
object A extends ATrait
Now I have a class B, where I need methods of Atrait. So I have injected it.
class B #Inject(a: ATrait) {
//code
}
I have also given the binding in Guice module class.
class GuiceModule extends AbstractModule {
override def configure(): Unit = {
bind[ATrait].toInstance(A)
}
}
Now when I create an object of class B,
val b = new B()
It won't let me do that, so my question is if I have to pass manually object of ATrait. What is the use of Google Guice Injection?
I might have done some mistake because I am learning this. Please guide me if I have not understood something correctly.
Thanks in advance.
Guice doesn't work in that way. If you want a new root object you need to ask Guice for a new instance.
val injector = Guice.createInjector(new GuiceModule())
val a:ATrait = injector.getInstance(classOf[ATrait])
I've been following this article which describes how to achieve dependency injection in Scala via the Cake Pattern:
http://jonasboner.com/real-world-scala-dependency-injection-di/
I'm kind of new to Scala and I admit some of it went over my head, so far I've got the following working:
// Setup the component and interface
trait AccountRepositoryComponent {
val accountRepository: AccountRepositoryInterface
trait AccountRepositoryInterface {
def message: String
}
}
// An implementation
trait MyAccountRepositoryComponent extends AccountRepositoryComponent {
object AccountRepository extends AccountRepositoryInterface {
def message: String = "Hello"
}
}
// Object to configure which implementations to use and retrieve them
object ComponentRegistry extends MyAccountRepositoryComponent {
val accountRepository = AccountRepository
}
// Example service using the above
object AccountService {
val repo = ComponentRegistry.accountRepository
def say: String = repo.message
}
println(AccountService.say)
What I'm failing to understand is how I would now pass in a fake repository to Account Service, say to change the output to "Test" rather than "Hello"?
There are various ways this could be modified to achieve a workable result, depending on what counts as a workable result for your situation. I'll go through a simpler possibility here.
First, the ComponentRegistry needs to become a trait, so it can be mixed in to the AccountService:
// Trait to configure which component implementations to use and retrieve them
object ComponentRegistry extends MyAccountRepositoryComponent {
val accountRepository = AccountRepository
}
// Example service using the above
object AccountService extends ComponentRegistry {
def say: String = accountRepository.message
}
println(AccountService.say)
This should print "Hello" as before. To set up a test case, add the following:
// Test implementation
trait TestAccountRepositoryComponent extends AccountRepositoryComponent {
object AccountRepository extends AccountRepositoryInterface {
def message: String = "Test"
}
}
// trait to configure test component implementations
trait TestComponentRegistry extends TestAccountRepositoryComponent {
val accountRepository = AccountRepository
}
Now we can set up a service that uses the test components:
// Example service using the above
object AccountService extends TestComponentRegistry {
//val repo = ComponentRegistry.accountRepository
def say: String = accountRepository.message
}
println(AccountService.say)
This should print "Test".
Note that you would probably want your AccountService to define its functionality in terms of other mixins/traits, which would expect the appropriate components to be available (layered into the "cake"), but wouldn't know which implementation was in use. Eg:
trait CustomerApi {
self: AccountRepositoryComponent => // Expects an implementation of AccountRepositoryComponent to be mixed in
def say: String = accountRepository.message
}
Now the method say is implemented without knowing what version of AccountRepository it will interact with, but knowing one must be provided (checked at compile time). So we can write:
object AccountService extends CustomerApi with ComponentRegistry
object TestAccountService extends CustomerApi with TestComponentRegistry
Calling println(AccountService.say) will generate "Hello", while calling println(TestAccountService.say) will generate "Test".
This post provides a succinct example of that (followed by an interesting alternative).
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