I'd like to test a Finagle Resolver properly.
Let's get a sample code:
import com.twitter.finagle.{Addr, Address, Resolver}
import com.twitter.util._
class DummyResolver extends Resolver {
override val scheme: String = "sample"
override def bind(arg: String): Var[Addr] = {
val delegate = SomeFactory.fromArgs(arg).build()
Var.async(Addr.Pending: Addr)(u => addrOf(u)(delegate))
}
}
The use of a static factory prevents me from unit-testing the resolver.
As far as I know, the only way to provide the resolver to Finagle is to declare it into the com.twitter.finagle.Resolver file in META-INF/services. Thus, I cannot provide an instance myself.
Given those constraints, how to design the resolver to either:
be able to provide an instance of the delegate,
or be able to properly test the behavior (and mock the delegate)?
Related
Context: I am trying to capture multiple events in our api using serilog and the elastic search sink, these events include: GET actions(regular web api flow) as well as login attempts (Owin).
I am registering serilog like this:
container.RegisterConditional(
typeof(ICustomLogger),
c => typeof(CustomLogger<>).MakeGenericType(
c.Consumer?.ImplementationType ?? typeof(object)),
Lifestyle.Singleton,
c => true);
I am doing this for Owin registration:
app.Use(async (context, next) =>
{
using (var scope = container.BeginExecutionContextScope())
{
await next.Invoke();
}
});
Then when I call container.Verify(); the logger constructor gets called(as expected).
However when I call the logger from my OAuthAuthorizationServerProvider implementation like this:
var logger = ObjectFactory.GetInstance<ICustomLogger>(); the constructor gets called again, meaning the singleton is not really a singleton anymore, I am totally aware of the service locator antipattern(don't really have much time to refactor that piece right now), what is interesting is that if I change the logger registration to the following (getting rid of the type piece) then only one instance is created:
container.RegisterSingleton(typeof(ICustomLogger), typeof(CustomLogger))
The reason why I am trying to use the first option is because I want to be able to use .ForContext(typeof(T)); for serilog, and in case you are wondering how I am registering the ObjectFactory piece here it is:
Class:
public static class ObjectFactory
{
public static Container container;
public static void SetContainer(Container container)
{
ObjectFactory.container = container;
}
public static T GetInstance<T>() where T : class
{
return container.GetInstance<T>();
}
}
Registration(from my main bootstrapper):
ObjectFactory.SetContainer(container);
So my main question is: Why is only one instance created with RegisterSingleton but multiple are created with RegisterConditional and Lifestyle.Singleton?
The reason multiple instances are created has nothing to do with the fact that you are using your ObjectFactory, but simply because different closed versions of CustomLogger<T> are created:
A CustomLogger<object> is created when resolved as root type (by calling GetInstance<ICustomLogger>()
A CustomLogger<Service1> is created when ICustomLogger is injected into Service1.
Because a CustomLogger<object> is a different type than a CustomLogger<Service1>, it is impossible to have just one instance for both types. They both have to be created. This might seem weird, but consider these two classes:
public class Service1
{
public Service1(ICustomLogger logger) { }
}
public class Service2
{
public Service2(ICustomLogger logger) { }
}
At runtime, considering these two definitions, you want to create object graphs similar to the following:
var s1 = new Service1(new CustomLogger<Service1>());
var s2 = new Service2(new CustomLogger<Service2>());
In the above case, the CustomLoggers are not cached and are, therefore, effectively transients. You might try to rewrite this to the following, but that would not be the same:
ICustomLogger logger = new CustomLogger<Service1>();
var s1 = new Service1(logger);
var s2 = new Service2(logger);
Now both service get the same single instance. However, this means that Service2 gets a CustomLogger<Service1> which is not what you configured. You configured the dependency to be this:
typeof(CustomLogger<>).MakeGenericType(c.Consumer.ImplementationType)
Consequence of this is that when Service2 starts to log, it will look like if the messages are coming from Service1. This would likely be incorrect behavior. Otherwise, you could have simply called RegisterSingleton<ICustomLogger, CustomLogger<Service1>>().
This all means that the Singleton guarantee for a RegisterConditional that uses an implementation-type factory (as in your example) only holds for the specified closed generic type.
Note that RegisterConditional isn't the only part in Simple Injector where you see this behavior. The following registrations do have the same effect:
container.RegisterSingleton(typeof(IFoo<>), typeof(Foo<>));
container.RegisterDecorator(typeof(IFoo<>), typeof(FooDecorator<>), Lifestyle.Singleton);
In both these cases multiple instances of closed generic versions of Foo<T> and FooDecorator<T> can be created, but Simple Injector guarantees that there is only one instance of every closed-generic version of Foo<T>. With RegisterDecorator<T>, however, even that is not guaranteed. Consider this example:
container.Collection.Append<ILogger, Logger1>(Lifestyle.Singleton);
container.Collection.Append<ILogger, Logger2>(Lifestyle.Singleton);
container.RegisterDecorator<ILogger, LoggerDecorator>(Lifestyle.Singleton);
In this case, a collection of ILogger components is registered where each ILogger element will be wrapped with a LoggerDecorator. Because a LoggerDecorator can only depend on either Logger1 or Logger2, but not both, Simple Injector will have to create a new LoggerDecorator instance for each element. If the LoggerDecorator would be cached as a true Singleton, this would be the result:
private static ILogger logger = new LoggerDecorator(new Logger1());
private static loggers = new[] { logger, logger };
As there is only 1 single LoggerDecorator, this decorator depends on Logger1, which means that the collection of loggers only has two elements that both point to the same Logger1 instance. There is no Logger2.
This information is reflected in the following Simple Injector documentation sections:
Aspect-Oriented Programming - Applying Lifestyles to Decorators
Lifetime Management - Generics and Lifetime Management
I have faced a well-known scenarios whereby I really need to move a number of utilities private functions (that should not have been there in the first place) from my Service class to a utility class. My question is around using service methods in a utility class. I have attempted at the following refactoring:
class Utils(
val serviceIneed : ServiceIneed) {
companion object {
private val someMapper = ObjectMapperConfig.mapper
}
fun someUtility(): ResponseEntity<Any> {
// lots of stuff
return serviceIneed.someFunction()
}
}
Then this is the other service where I need to use the method I have moved to the newly created utility class:
class anotherService(
private val serviceIneed: ServiceIneed
) {
fun someMethod() {
// lots of things happening
val utilityUsage = Utils(serviceIneed).someUtility()
}
}
Is this the correct way to go about this? Can you recommend any approach on refactoring service classes in a way that only service-oriented methods and not helper ones remain in my Service class?
Thank you
I am getting errors in my IDE about:
Raw use of parameterized class 'GenericContainer' Inspection info:
Reports any uses of parameterized classes where the type parameters
are omitted. Such raw uses of parameterized types are valid in Java,
but defeat the purpose of using type parameters, and may mask bugs.
I've checked documentation and creators use everywhere raw type also:
https://www.testcontainers.org/quickstart/junit_4_quickstart/
f.e.:
#Rule
public GenericContainer redis = new GenericContainer<>("redis:5.0.3-alpine")
.withExposedPorts(6379);
I dont understand this approach. Can Anyone explain how should I parametrize GenericContainer<>?
Testcontainers uses the self-typing mechanism:
class GenericContainer<SELF extends GenericContainer<SELF>> implements Container<SELF> {
...
}
This was a decision to make fluent methods work even if the class is being extended:
class GenericContainer<SELF extends GenericContainer<SELF>> implements Container<SELF> {
public SELF withExposedPorts(Integer... ports) {
this.setExposedPorts(newArrayList(ports));
return self();
}
}
Now, even if there is a child class, it will return the final type, not just GenericContainer:
class MyContainer extends GenericContainer< MyContainer> {
}
MyContainer container = new MyContainer()
.withExposedPorts(12345); // <- without SELF, it would return "GenericContainer"
FYI it is scheduled for Testcontainers 2.0 to change the approach, you will find more info in the following presentation:
https://speakerdeck.com/bsideup/geecon-2019-testcontainers-a-year-in-review?slide=74
If you declare it like
PostgreSQLContainer<?> container = new PostgreSQLContainer<>(
"postgres:9.6.12")
.withDatabaseName("mydb");
the warning also goes away.
I am working with a kotlin and spring project, Now I am trying to do the test of some service, which has some dependencies, I am having some problems, in order to get a success test. Maybe I my design is not good enough, moreover I have problems trying to call the method from the spy object, I am getting the issue: Cannot invoke real method 'getClubhouseFor' on interface based mock object. This is my code, Could you give me any idea about what I am doing bad.
Thanks in advance!!!!
This is my code:
import com.espn.csemobile.espnapp.models.UID
import com.espn.csemobile.espnapp.models.clubhouse.*
import com.espn.csemobile.espnapp.services.clubhouse.AutomatedClubhouseService
import com.espn.csemobile.espnapp.services.clubhouse.ClubhouseService
import com.espn.csemobile.espnapp.services.clubhouse.StaticClubhouseService
import com.espn.csemobile.espnapp.services.clubhouse.contexts.ClubhouseContext
import com.espn.csemobile.espnapp.services.core.CoreService
import rx.Single
import spock.lang.Specification
class ClubhouseServiceImplTest extends Specification {
StaticClubhouseService staticClubhouseService = GroovyStub()
AutomatedClubhouseService automatedClubhouseService = GroovyStub()
CoreService coreService = GroovyStub()
ClubhouseContext clubhouseContext = GroovyMock()
Clubhouse clubHouse
ClubhouseLogo clubhouseLogo
ClubhouseService spy = GroovySpy(ClubhouseService)
void setup() {
clubhouseLogo = new ClubhouseLogo("http://www.google.com", true)
clubHouse = new Clubhouse(new UID(), "summaryType", ClubhouseType.League, new ClubhouseLayout(), "summaryName", "MLB", clubhouseLogo, "http://www.google.com", "liveSportProp",new ArrayList<Integer>(), new ArrayList<ClubhouseSection>(),new ArrayList<ClubhouseAction>(), new HashMap<String, String>())
}
def "GetClubhouseFor"() {
given:
staticClubhouseService.getClubhouseFor(clubhouseContext) >> buildClubHouseMockService()
// The idea here is to get different responses it depends on the class of call.
automatedClubhouseService.getClubhouseFor(clubhouseContext ) >> buildClubHouseMockService()
spy.getClubhouseFor(clubhouseContext) >> spy.getClubhouseFor(clubhouseContext)
when:
def actual = spy.getClubhouseFor(clubhouseContext)
then:
actual != null
}
def buildClubHouseMockService(){
return Single.just(clubHouse)
}
}
The next are the classes involved in the test:
import com.espn.csemobile.espnapp.models.clubhouse.*
import com.espn.csemobile.espnapp.services.clubhouse.contexts.ClubhouseContext
import com.espn.csemobile.espnapp.services.core.CoreService
import org.springframework.context.annotation.Primary
import org.springframework.context.annotation.ScopedProxyMode
import org.springframework.stereotype.Service
import org.springframework.web.context.annotation.RequestScope
import rx.Single
interface ClubhouseService {
fun getClubhouseFor(context: ClubhouseContext): Single<Clubhouse?>
}
#Service
#RequestScope(proxyMode = ScopedProxyMode.NO)
#Primary
class ClubhouseServiceImpl(private val clubhouseContext: ClubhouseContext,
private var staticClubhouseService: StaticClubhouseService,
private var automatedClubhouseService: AutomatedClubhouseService,
private val coreService: CoreService?): ClubhouseService {
override fun getClubhouseFor(context: ClubhouseContext): Single<Clubhouse?> {
return staticClubhouseService.getClubhouseFor(clubhouseContext).flatMap { clubhouse ->
if (clubhouse != null) return#flatMap Single.just(clubhouse)
return#flatMap automatedClubhouseService.getClubhouseFor(clubhouseContext)
}
}
}
Well, first of all GroovySpy or GroovyStub do not make sense for Java or Kotlin classes because the special features of Groovy mocks are only available for Groovy classes. So don't expect to be able to mock constructors or static methods that way, if that was the reason for the usage. This is also documented here:
When Should Groovy Mocks be Favored over Regular Mocks? Groovy mocks should be used when the code under specification is written in Groovy and some of the unique Groovy mock features are needed. When called from Java code, Groovy mocks will behave like regular mocks. Note that it isn’t necessary to use a Groovy mock merely because the code under specification and/or mocked type is written in Groovy. Unless you have a concrete reason to use a Groovy mock, prefer a regular mock.
As for your problem with the spy, you cannot use a spy on an interface type. This is documented here:
A spy is always based on a real object. Hence you must provide a class type rather than an interface type, along with any constructor arguments for the type.
So either you just switch to Mock or Stub, both of which work on interface types, or you spy on the implementation class instead. In any case, my main suggestion is to read the documentation first and then try to use a new tool like Spock. My impression is that you have not used Spock before, but of course I could be wrong.
From my controller I would like to dynamically select a service based on a parameter.
Currently I have a base service and some other services that extent this base service. Based on the parameter I call a class that does creates a bean name based on the param and eventually calls the following:
import org.codehaus.groovy.grails.web.context.ServletContextHolder as SCH
import org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes as GA
class Resolver {
def ctx
def getBean(String beanName) {
if(!ctx) {
ctx = SCH.servletContext.getAttribute(GA.APPLICATION_CONTEXT)
}
return ctx."${beanName}"
}
}
This returns the service I want. However I feel rather dirty doing it this way. Does anyone have a better way to handle getting a service (or any other bean) based on some parameter?
Thank you.
ctx."${beanName}" is added to the ApplicationContext metaclass so you can do stuff like def userService = ctx.userService. It's just a shortcut for ctx.getBean('userService') so you could change your code to
return ctx.getBean(beanName)
and it would be the same, but less magical.
Since you're calling this from a controller or a service, I'd skip the ServletContextHolder stuff and get the context by dependency-injecting the grailsApplication bean (def grailsApplication) and getting it via def ctx = grailsApplication.mainContext. Then pass it into this helper class (remember the big paradigm of Spring is dependency injection, not old-school dependency-pulling) and then it would be simply
class Resolver {
def getBean(ctx, String beanName) {
ctx.getBean(beanName)
}
}
But then it's so simple that I wouldn't bother with the helper class at all :)