Integration testing for a single service mocking/stubbing some of the injected components - integration-testing

I've read hundred of posts and pages but I'm unable to figure the right way to do integration testing mocking just some components.
This is the scenario: I've an application created using Spring Boot (1.2-snapshot) and among various spring libraries, also spring data JPA.
I've several services, for example Service1 and Service2, and they use other components and repositories managed by Spring Data.
If I want to test all the services for a complete integration testing using an embedded hsql database I declare a class this way in my test package:
#Transactional
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = AppConfig.class)
public class IntegrationTest {
#Autowired
private Service1 s1;
#Autowired
private Service2 s2;
[... test methods ...]
}
Where the AppConfig class is instead in my main package, and is defined this way:
#ComponentScan
#Configuration
#EnableAutoConfiguration
public class AppConfig {
public static void main(String[] args) {
SpringApplication.run(AppConfig.class, args);
}
}
During the integration testing a complete spring context get defined, all the spring data repositories are built and instantiated as usuale and everything works fine as expected.
But there 2 are scenarios where I need different goals:
1) I want to test just one service at a time (e.g.: Service1), for example because Service2 is very slow to initialize, and I want to test it in a different test class.
How do I achieve this goal? The problem is that I still need all the Dependency Injection, and in particular all the spring data manages repositories that Service1 autowires on itself. If I was not using spring-data repositories I could new() the Service1 class by myself and then wire all the dependencies by hand, even this would be very cumbersome.
2) While testing Service1, I would like do mock/stub just one of all his dependencies. For example I would simulate a component that in production connects to external services.
I don't know how to selectively inject a stubbed object on the spring context while continuing to use all the others as usual.
Some help on the subject would be very welcome.

Instead of using Mockito mocks you can create different test beans that are set up on different profiles and then execute the tests with those profiles.
FOr example (of course it's just a vision of how you can do it not the exact solution) you could add a profile 'fast' and run your tests with #ActiveProfiles('fast'). Then you would have test configurations annotated with #Profile('fast') that would set up all the beans that you need

Related

Configuration Spring - Kafka for many clusters Kafka? What is best solution?

I see people duplicating code to configure kafka for each cluster :(
Is it really necessary to configure Consumer Factory and Producer Factory with different settings every time? And do not use Spring Boot Kafka starter in any way?
If you use similar properties for each cluster, you can override the bootstrap.servers property for each #KafkaListener and/or create multiple #KafkaTemplates with the same override.
Then, the same factories can be used.
See https://docs.spring.io/spring-kafka/docs/current/reference/html/#annotation-properties
#KafkaListener(topics = "myTopic", groupId = "group", properties = {
"max.poll.interval.ms:60000",
ConsumerConfig.MAX_POLL_RECORDS_CONFIG + "=100"
})
/**
* Create an instance using the supplied producer factory and properties, with
* autoFlush false. If the configOverrides is not null or empty, a new
* {#link DefaultKafkaProducerFactory} will be created with merged producer properties
* with the overrides being applied after the supplied factory's properties.
* #param producerFactory the producer factory.
* #param configOverrides producer configuration properties to override.
* #since 2.5
*/
public KafkaTemplate(ProducerFactory<K, V> producerFactory, #Nullable Map<String, Object> configOverrides) {
Spring Boot auto-configuration is by convention for the common microservices use-case: one thing, but simple and clear.
What you are asking is out of Spring Boot scope: the properties configuration is applied only for one ConsumerFactory and one ProducerFactory. As long as you need to connect to different clusters you are on your own. Having a custom ConsumerFactory bean will lead Spring Boot auto-configuration to back off.
You probably can look into a child ApplicationContext configuration with its own provided set of properties. But will it be easier to just have custom configuration for each cluster as you would do without Spring Boot with just a plain Apache Kafka client?
I have no idea if there is some federation solution for Apache Kafka. But that's still out of Spring for Apache Kafka and Spring Boot scope.

Can Prism use .NET Core's built in Dependency Injection?

I'd like to start a WPF app using .NET Core 3.1
Can Prism make use of .Net Core's built-in DI (IServiceCollection) or do I have to use something like Unity?
If Prism cannot use the built-in DI, can they exist side-by-side?
Can Prism make use of .Net Core's built-in DI
From what I've seen you can't really replace Prism's DryIot with the ASP.NET Core build-in one. Mainly DryIot is more feature-full than the ServiceCollection API. There is this opensource package I've found that has an IContainerExtension implementation using ServiceCollection, but per the developer's own words this is more of a proof of concept rather than sable solution.
If Prism cannot use the built-in DI, can they exist side-by-side?
Yes, they can. With a caveat - you cannot simply register a service in ServiceCollection and expect to be able to inject that service directly in your App, Modules and ViewModels. This will fail because those files are managed by the Prism framework and thus injection will only work for services you have registered using the IContainerRegistry interface.
Benefits
Why would you do it? As the build-in IoT container the ServiceCollection API is well-known, thus it will be simpler for .Net developers. Furthermore you can structure you non-WPF projects to register services using the default container thus allowing them to be completely decoupled from your Desktop project. This is very good for more complex architectures like Domain-Driven Design.
Let's consider the following project structure:
solution
-- Desktop // Prism WPF application, containing only views and models
-- Application // Class library, containing operational logic.
Let's say that as a part of the Application project you need an IUserService which holds information about the current user that has to be populated in-memory when the user authenticates in the Desktop app. A registration method would look like this:
public IServiceCollection AddServices(this IServiceCollection services)
{
services.AddSingleton<IUserService, UserService>()
}
So now we need to inject it inside the Desktop project. I suggest two methods:
Simple
Seemless
Simple
This approach requires very simple startup configuration. The caveat is that you will not be able to inject your services directly in the constructor, but through the IServiceProvider interface.
Reference Microsoft.Extensions.DependencyInjection
Call your service registration method in App:
protected override void RegisterTypes(IContainerRegistry container)
{
// Build service provider using the ServiceCollection API
var provider = new ServiceCollection()
.AddServices()
.BuildServiceProvider();
// Register IServiceProvider within DryIot and provide
// a factory method to retrieve the service instance
container.Register<IServiceProvider>(() => provider);
}
Inject IServiceProvider where you need IUserService. For this example I'll use a Prism Module:
public class Module : IModule
{
private readonly IUserService userService;
public Module(IServiceProvider serviceProvider)
{
this.userService = serviceProvider.GetService<IUserService>();
}
...
private void Authenticate()
{
this.userService.IsAuthenticated = true;
}
}
That's it, you can now use your ServiceCollection registered dependency wherever you can access the IServiceProvider through Prism injection. This is the approach I recommend, because we are simply wrapping the .Net container in Prism's.
Seemless
This is where it gets a bit more interesting. Full disclaimer - you might encounter problems using this approach. I have not yet tested this beyond the most basic use-case. The only advantage this method offers is that you will be able to directly inject services in the constructor, instead of having to go through the IServiceProvider.
In its essence this method is simply looping through the ServiceCollection and registering all services directly in the Prism container. If we take a look at the implementation of ServiceCollection - it is simply a list of ServiceDescriptors. Upon further inspection we observe that ServiceDescriptior contains a bunch of constructors. We'll ignore those and focus on the properties:
ServiceType - the type that will be used when injecting
ImplementationType - type of the implementation to be injected
ImplementationInstance - instance of the implementation type
ImplementationFactory - factory delegate that returns an instance of the implementation type
LifeTime - Singleton, Scoped or Transient type
Let's now inspect the IContainerRegistry interface. We'll see that there are a lot of overloads of Register that accept Types, object and delegates.
Using that knowledge we can now create an adapter from ServiceDescriptor to registration of IContainerRegistry. The below implementation will only focus on Transient services, but the difference between service lifetimes is simply which registry method we call - Register for a Transient and RegisterSingleton for well Singletons.
Create and Adapter class with static method that accepts IContainerRegistry and ServiceDescriptor arguments:
public static void Register(IContainerRegistry container, ServiceDescriptor service)
{
// In case an implementation instance is provided we simply need to register it
if (service.ImplementationInstance != null)
{
containter.Register(service.ServiceType, service.ImplementationInstance);
}
// In case a factory is provided we have a bit more work.
// We need to modify it in order for it to be usable by the DryIot container
else if (service.ImlementationFactory != null)
{
var factory = service.ImplementationFactory;
var dryIotFactory = dryIotProvider =>
{
var provider = dryIotProvider.Resolve<IServiceProvider>();
return factory(provider);
};
container.Register(service.ServiceType, dryIotFactory);
}
// If no implementation or factory is provided then we simply register the
// types and let the container create the implementation instance on its own.
else
{
container.Register(service.ServiceType, service.ImplementationType);
}
}
The most tricky part here is the factory. To better understand factories in service-registration know that sometimes you may need access to other services to provide the correct implementation instance. For example if IHttpClient is registered you need to provide the IAuthorizationSerice with HttpAuthorizationService implementation instead of DesktopAuthorizationService.
Essentially we wrap the original factory method with a DryIot-compatible factory (accepts instance of DryIot container) that can supply the original factory with IServiceProvider instance.
Reference Microsoft.Extensions.DependencyInjection
Call your service registration method in App:
protected override void RegisterTypes(IContainerRegistry container)
{
var services = new ServiceCollection().AddServices()
foreach (var service in services)
{
Adapter.Register(container, service);
}
}
Inject IUserService directly in the module constructor:
public class Module : IModule
{
private readonly IUserService userService;
public Module(IUserService userService)
{
this.userService = userService;
}
}
Final thoughts
Again, I recommend the simple approach. Simplicity means lower learning curve and less room for errors. The inconvenience is minor in comparison.
Another fair warning - this is not production ready code. Especially the seemless method. I have yet to "battle-test" this implementation, but it might point you in the right direction.
If anyone has feedback/opinions I would be glad to read about it :)
Can Prism make use of .Net Core's built-in DI
Short Answer, NO
Here is a comment by #brianlagunas (The creator of Prism)
As I mentioned, we can't use IServiceProvider as we are in netstandard 1.0. The ServiceProvider and IServiceCollection is in netstandard 2.0. Also, there are a number of features that Prism needs that are to limited in the IServiceCollection implementation. Such as named instances and registrations, as well as a mutable container.
here is a comment by #dansiegel
I have spent a lot of time discussing this issue, and ultimately we cannot directly rely on IServiceProvider and IServiceCollection for a variety of reasons that extend beyond whether or not they are available.
here is the another comment also by
#brianlagunas
do I have to use something like Unity?
The ServiceCollection is "something like Unity". And, yes, you can use it with prism:
Create an IContainerExtension implementation that redirects to ServiceCollection
Derive from PrismApplicationBase and return your container extension from CreateContainerExtension

How can I execute a method by accessing autowired object in spring MVC from separate standalone java application

Let's we have a class in webapp.war (spring MVC 4.2.2.RELEASE)
public class SomeClass{
#Autowired
private MyInterface implObject;
public void method1(){
implObject.doSomething();
// statements ...
}
}
and another class in standalone.jar
public class MainClass{
public static void main(String[] args){
// want to create object of SomeClass
// or execute doSomething() ...
}
}
Note: application will be deployed in clustered environment, standalone.jar will be executed by shell script (it will be registered in crontab).
I want to schedule some job (fetch records and send to weblogic queue JMS ...), using Unix crontab. and don't want to repeat DB operation separately (in standalone.jar).
Please also suggest if I can make standalone.jar small in size.
Quartz or similar implementation is not expected in my case.
Thank you.
I solved this problem by extracting necessary part of webapp.war, into app.jar.
Scheduling and batch configured using crontab.
Used maven build tool i.e maven-shade.
Any required configuration left to spring.

How do I enable matrix variable support without clobbering Spring Boot configuration?

I'd like to both use Spring Boot to take advantage of JacksonAutoConfiguration and enable matrix variables for my controllers, which requires calling RequestMappingHandlerMapping.setRemoveSemicolonContent(false).
When this trivial Gist is run without the WebMvcConfiguration being scanned in, the output is
{"dateTime":1404244199372}
When it is scanned in, the output is
{"dateTime":{"year":2014,"era":1,"dayOfYear":182,"dayOfWeek":2,"dayOfMonth":1,"centuryOfEra":20,"yearOfEra":2014,"yearOfCentury":14,"weekyear":2014,"monthOfYear":7,"weekOfWeekyear":27,"secondOfDay":76856,"minuteOfDay":1280,"hourOfDay":21,"minuteOfHour":20,"secondOfMinute":56,"millisOfSecond":807,"millisOfDay":76856807,"chronology":{"zone":{"fixed":false,"uncachedZone":{"cachable":true,"fixed":false,"id":"Europe/Berlin"},"id":"Europe/Berlin"}},"zone":{"fixed":false,"uncachedZone":{"cachable":true,"fixed":false,"id":"Europe/Berlin"},"id":"Europe/Berlin"},"millis":1404242456807,"afterNow":false,"beforeNow":true,"equalNow":false}}
It's quite hard to tell why this is happening, and I'm still not sure after digging around in ObjectMappers, JodaModule, and MappingJackson2HttpMessageConverter.
Any idea how to configure Spring to leverage both Spring Boot and be able to support matrix variables?
Update: Other breakages caused by scanning in DelegatingWebMvcConfiguration include Boot's http.mappers.jsonPrettyPrint support.
As described here, the following does the trick with Spring Boot 1.2.
#Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
#Override
public void configurePathMatch(PathMatchConfigurer configurer) {
UrlPathHelper urlPathHelper = new UrlPathHelper();
urlPathHelper.setRemoveSemicolonContent(false);
configurer.setUrlPathHelper(urlPathHelper);
}
}
I think you might just have to copy the bits you need from the boot autoconfiguration. Or raise an issue with Spring Framework to get support for the semicolon feature added to WebMvcConfigurer. One other thing that might just work is to add a RequestMappingHandlerMapping directly (rather than using a base class for your config).

File() FileStream in web app

I've made desktop app, and i want it to work also as an web app.
I get errors on lines with File() type and FileStream, is there any way to bypass this ?
To piggyback on #Florian F's correct response, here is how you might implement it:
Create an interface to abstract your file access
public interface IGetTheStuffService {
function getSomeTofu():Tofu;
}
Create a file-based implementation
public class FileStuffService implements IGetTheStuffService {
public function getSomeTofu():Tofu {
// File-based implementation
}
}
And an HTTP-based implementation
public class HTTPStuffService implements IGetTheStuffService {
public function getSomeTofu():Tofu {
// HTTP-based implementation
}
}
In your consumer, rely on the IGetTheStuffService
[Inject] public var tofuService:IGetTheStuffService;
public function doSomeStuff():void {
var tofu:Tofu = tofuService.getSomeTofu();
// act on the tofu
}
Notice the Inject meta tag. This is where your Dependency Injection (DI) system would push in your dependency based on the configuration (FileStuffService for Air apps or HTTPStuffService for Web apps). Parsley and RobotLegs use [Inject] where fiex-ioc uses [IocBind]
Of course, you could go without a DI container... you would just inject the parameter directly.
But you get the idea... a pretty simple pattern, actually.
The File() class is only available for AIR applications, that's why you get the error.
This is how I would do it :
You need to isolate platform dependant code and put in a separate library.
Other code that work the same whatever the platform should be in another isolated library.
Create 2 projects that will be simple wrappers. A Flex project that is only coupled to the common code. An AIR Project that is coupled to both common and platform dependant code.
You'll then probably need to use Interfaces at some time to switch between implementations that are platform specific

Resources