In Pax-exam test classes. We have to provide the configuration as follows. to create the container.
#Configuration
public Option[] config() {
setup();
return options(
mavenBundle().artifactId("testng").groupId("org.testng").versionAsInProject(),
mavenBundle().artifactId("sample1").groupId("sample2").versionAsInProject(),
mavenBundle().artifactId("sample3").groupId("sample4").versionAsInProject()
}
Instead of defining this in every test class, can't we provide a configuration to provision the container?..
You can use a ConfigurationFactory service. Or simply factor out your options to some static helper method and invoke this from the #Configuration method of your tests.
Related
I came across an interesting article: AOP Aspects as mocks in JUnit
Since I have requirement to mock multiple final and private static variables, I am planning to use AOP in place of reflection or PowerMockito as they are causing issues with SpringJUnit4ClassRunner.
Is there any way I can use #Aspect for test classes without using the annotation #EnableAspectJAutoProxy? (I want to use an aspect targeting class X only in one test case.)
This is a sample of what I want to do.
The question is answered(adding for discussion on what could be done)
//External class
public final class ABC(){
public void method1() throws Exception {}
}
#Service
public void DestClass() {
private static final ABC abc = new ABC();
public Object m() {
// code (...)
try {
abc.method1();
}
catch(Exception e) {
// do something (...)
return null;
}
// more code (...)
}
}
Spring framework allows to programmatically create proxies that advise target objects , without configuring through #EnableAspectJAutoProxy or <aop:aspectj-autoproxy>
Details can be found in the documentation section : Programmatic Creation of #AspectJ Proxies and the implementation is pretty simple.
Example code from the documentation.
// create a factory that can generate a proxy for the given target object
AspectJProxyFactory factory = new AspectJProxyFactory(targetObject);
// add an aspect, the class must be an #AspectJ aspect
// you can call this as many times as you need with different aspects
factory.addAspect(SecurityManager.class);
// you can also add existing aspect instances, the type of the object supplied must be an #AspectJ aspect
factory.addAspect(usageTracker);
// now get the proxy object...
MyInterfaceType proxy = factory.getProxy();
Please note that with Spring AOP , only method executions can be adviced. Excerpt from the documentation
Spring AOP currently supports only method execution join points
(advising the execution of methods on Spring beans). Field
interception is not implemented, although support for field
interception could be added without breaking the core Spring AOP APIs.
If you need to advise field access and update join points, consider a
language such as AspectJ.
The document shared with the question is about aspectj and without providing the sample code to be adviced it is hard to conclude if the requriement can acheived through Spring AOP. The document mentions this as well.
One example of the integration of AspectJ is the Spring framework,
which now can use the AspectJ pointcut language in its own AOP
implementation. Spring’s implementation is not specifically targeted
as a test solution.
Hope this helps.
--- Update : A test case without using AOP ---
Consider the external Class
public class ABCImpl implements ABC{
#Override
public void method1(String example) {
System.out.println("ABC method 1 called :"+example);
}
}
And the DestClass
#Service
public class DestClass {
private static final ABC service = new ABCImpl();
protected ABC abc() throws Exception{
System.out.println("DestClass.abc() called");
return service;
}
public Object m() {
Object obj = new Object();
try {
abc().method1("test");
} catch (Exception e) {
System.out.println("Exception : "+ e.getMessage());
return null;
}
return obj;
}
}
Following test class autowires the DestClass bean with overridden logic to throw exception . This code can be modified to adapt to your requirement.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = { DestClassSpringTest.TestConfiguration.class })
public class DestClassSpringTest {
#Configuration
static class TestConfiguration {
#Bean
public DestClass destClass() {
return new DestClass() {
protected ABC abc() throws Exception {
// super.abc(); // not required . added to demo the parent method call
throw new Exception("Custom exception thrown");
}
};
}
}
#Autowired
DestClass cut;
#Test
public void test() {
Object obj = cut.m();
assertNull(obj);
}
}
Following will be the output log
DestClass.abc() called // this will not happen if the parent method call is commented in DestClassSpringTest.TestConfiguration
Exception : Custom exception thrown
The article you are referring to is using full AspectJ, not Spring AOP. Thus, you do not need any #EnableAspectJAutoProxy for that, just
either the AspectJ load-time weaver on the command line when running your test via -javaagent:/path/to/aspectjweaver.jar
or the AspectJ compiler activated when compiling your tests (easily done via AspectJ Maven plugin if you use Maven)
Both approaches are completely independent of Spring, will work in any project and even when using Spring also work when targeting execution of third party code because no dynamic proxies are needed unlike in Spring AOP. So there is no need to make the target code into a Spring bean or to create a wrapper method in your application class for it. When using compile-time weaving you can even avoid weaving into the third party library by using call() instead of execution() pointcut. Spring AOP only knows execution(), AspectJ is more powerful.
By the way: Unfortunately both your question and your comment about the solution you found are somewhat fuzzy and I do not fully understand your requirement. E.g. you talked about mocking final and private static variables, which would also be possible in other ways with AspectJ by using set() and/or get() pointcuts. But actually it seems you do not need to mock the field contents, just stub the results of method calls upon the objects assigned to those fields.
Requirement
For Cloud, datastore needs to change namespace dynamically. (example store kind as per company Name)
Used Spring cloud DataRepository with Springboot for same
Issue
We need to declare spring.cloud.gcp.datastore.namespace in application.properties which is static.
Is there any way to change this dynamically with CRUDReposity of spring cloud
Thanks in advance
You can change anything you want in your application.properties at runtime using Spring Cloud Config.
Spring Cloud Config provides server-side and client-side support for externalized configuration in a distributed system. With the Config Server, you have a central place to manage external properties for applications across all environments. The concepts on both client and server map identically to the Spring Environment and PropertySource abstractions, so they fit very well with Spring applications but can be used with any application running in any language.
Just as a quick example on how you can use this , you should firstly add the dependency : eg gradlecompile group: 'org.springframework.cloud', name: 'spring-cloud-starter', version: '1.1.1.RELEASE', then you need to add the #RefreshScope on the desired configuration bean.
You will be able to view your current config at a certain endpoint, like "applicationConfig: [classpath:/application.properties]": {
"my.property": "value1",
etc
And then you can change the properties as you wish doing a POST request like :
curl -X POST http://localhost:8080 -d my.property=value2
There is also a nice article about dynamically reloading the properties in a Spring application here. It is nice because they actually display more ways that you can achieve that.
You can use DatastoreNamespaceProvider which can dynamically return needed namespace.
Was added in this PR PR
Also see this discussion here and this recommendation
#Component
#RequiredArgsConstructor
#Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
public class HeaderValueProvider implements Supplier<String>, DatastoreNamespaceProvider {
private final HttpServletRequest httpServletRequest;
#Override
public String get() {
return httpServletRequest.getHeader("someHeader");
}
}
And this
#Component
public class UserContextProvider implements DatastoreNamespaceProvider, Consumer<UUID> {
private static final ThreadLocal<UUID> USER_CONTEXT = new ThreadLocal<>();
#Override
public String get() {
return ofNullable(USER_CONTEXT.get())
.map(UUID::toString)
.orElse(null);
}
#Override
public void accept(UUID uuid) {
USER_CONTEXT.set(uuid);
}
}
I have a test defined with:
#ComponentScan(basePackages = { ... })
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = { AppConfig.class })
#WebMvcTest(secure = false)
public class MyTest extends AbstractJUnit4SpringContextTests {
#Autowired SomeClass target;
#Test public void test() { Assert.assertTrue(target != null); } // MCVE
}
Here's my ContextConfiguration class:
#Configuration
public class AppConfig {
#Bean
#ConfigurationProperties(prefix = "datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
#Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
#Bean
ServletWebServerFactory servletWebServerFactory() {
return new TomcatServletWebServerFactory();
}
}
This test works fine, but it wastes a lot of time in MVC initialization due to the #WebMvcTest annotation. This particular test does not require any MVC functionality. The annotation ended up in there as a result of trial-and-error, to get the #Autowired annotation to work correctly. But now I want to remove it.
So... I went ahead and removed the #WebMvcTest annotation. But then the test fails because apparently the #ComponentScan does not have any effect unless #WebMvcTest is present (which I now remember, is the reason I added it).
Here's the actual error message:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type '...' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
I tried adding #SpringBootTest but it made no difference.
If instead, I add #EnableAutoConfiguration, I get a different error:
java.lang.IllegalArgumentException: dataSource or dataSourceClassName or jdbcUrl is required.
What annotation am I missing?
EDIT:
Why removing WebMvcTest annotation from my test in SpringBoot application causes ComponentScan to fail?
Because you have not annotated the class in a way that Spring's IoC/Dependency injection can work correctly.
Now that the answer is clear, here are a couple of suggestions for you to try. They may or may not work depending upon how your project and dependencies etc are put together.
END EDIT:
This particular test does not require any MVC functionality.
You should consider using one of the more direct auto-configuration annotations for the your tests if you don't need all of MVC but do want auto configuration. For instance, it appears you are testing with some data system. Perhaps the #DataJpaTest or #JdbcTest annotations would provide a more streamlined approach. These will enable auto configuration (IoC and Dependency injection).
What annotation am I missing?
As written above, the annotation you are missing is #Configuration
This is counter intuitive here because this isn't a configuration class. But without an appropriate annotation that enables Dependency injection to occur, this is the only way to get this to work. Why?
From the docs:
public #interface ComponentScan
Configures component scanning directives for use with #Configuration classes.
So your choices are:
Use a different auto config annotation as suggested above
Add the #Configuration annotation
In our project I have modules scout.client, scout.server, scout.shared and backend.
Backend has no dependencies to scout.server and scout.shared, but scout.server has dependencies to backend.
Inside backend project I have all business logic and calling all outside services.
My problem is when I try to test scout services that use some service from backend.
Because scout provide some great tool for mocking beans, we defined our service inside backend as beans as :
BEANS.getBeanManager().registerClass(CarService.class);
BEANS.getBeanManager().registerClass(PartnerService.class);
Both, CarService.class and PartnerService.class are in backend.
When I try to write some tests and I add #BeanMock to service in test
#BeanMock
private IPartnerService partnerService;
I get mock, but then every return every function is null, even if I write
doReturn(PartnerBuilder.standardPartnerListWithOneElement()).when(this.partnerService)
.getPartners(any(Set.class));
If I debug in my test, before this test is called with debugger I can get :
partnerService.getPartners(...) -> return a list of person
what is right, but when class that is tested calles this service it return null.
I understand that this could be due to missing annotation on interface #ApplicationScoped. Without this there is no guarantee that only one bean is created, and when statement react on another copy of that bean...?
I could not add annotation on interface because backend has no dependencies to scout modules.
How could I handle this kind of cases?
Tested class is :
public class UtilityPartner {
/**
* Method return service bean for getting partners by ids.
*
* #return
*/
private static IPartnerService getPartnerService() {
return BEANS.get(IPartnerService.class);
}
public static String getPartnerName(final Long partnerId) {
if (partnerId == null) {
return "";
}
final List<Partner> partners =
(List<Partner>) getPartnerService().getPartners(Sets.newHashSet(partnerId));
if (partners == null || partners.isEmpty()) {
return "";
}
final Partner partner = partners.get(0);
return LookupUtil.createLookupDescription(partner.getId(), partner.getName());
}
}
test class is :
#RunWith(ServerTestRunner.class)
#RunWithSubject("anonymous")
#RunWithServerSession(ServerSession.class)
public class TestUtilityPartner {
#BeanMock
private IPartnerService partnerService;
#Before
public void init() {
doReturn(PartnerBuilder.standardPartnerListWithOneElement()).when(this.partnerService).getPartners(any(Set.class));
}
#Test
public void getPartnerName() {
final String name = UtilityPartner.getPartnerName(10L);
Assert.assertEquals("My name", name); // NAME IS ""
}
}
Using #BeanMock does not help here, because you are not using an application scoped service:
In the init method you are changing the local field partnerService. However, in your test you call UtilityPartner.getPartnerService, which is creating a new instance (with BEANS.get(IPartnerService.class)).
#BeanMock is more useful for convenience for mocking application scoped beans.
You can always register your beans manually as shown by Jmini. Please do not forget to unregister the bean again after the test!
We recommend using org.eclipse.scout.rt.testing.shared.TestingUtility.registerBean(BeanMetaData), which is automatically adding a testing order and removing #TunnelToServer annotations.
I think that you should register your mock instance in the Bean manager (See bean registration in the Scout Architecture Document). You should use a small order (-10 000 is recommended for tests), in order for your mock to win over the productive registration. The best approach is to use the TestingUtility class to register/unregister your mock. Do not forget to call the unregisterBean() method (in the method annotated with #After):
import java.util.Collections;
import org.eclipse.scout.rt.platform.BeanMetaData;
import org.eclipse.scout.rt.platform.IBean;
import org.eclipse.scout.rt.testing.shared.TestingUtility;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
public class TestUtilityPartner {
private IBean<?> beanRegistration;
#Before
public void init() {
partnerService = Mockito.mock(IPartnerService.class);
// Register the mock using the Bean meta information:
BeanMetaData beanData = new BeanMetaData(IPartnerService.class)
.withInitialInstance(partnerService)
.withApplicationScoped(true);
this.beanRegistration = TestingUtility.registerBean(beanData);
// Mockito behavior:
Mockito.doReturn(Collections.singletonList(new Partner(34L, "John Smith")))
.when(partnerService).getPartners(Mockito.any(Set.class));
}
#After
public void after() {
// Unregister the mocked services:
TestingUtility.unregisterBean(this.beanRegistration);
}
#Test
public void getPartnerName() {
String name = UtilityPartner.getPartnerName(10L);
Assert.assertEquals("10 - John Smith", name);
}
}
I am not sure what #BeanMock (org.eclipse.scout.rt.testing.platform.mock.BeanMock) is doing, but according to Judith Gull's answer it will not work:
Using #BeanMock does not help here, because you are not using an application scoped service:
In the init method you are changing the local field partnerService. However, in your test you call UtilityPartner.getPartnerService, which is creating a new instance (with BEANS.get(IPartnerService.class)).
#BeanMock is more useful for convenience for mocking application scoped beans.
I'm creating a service that uses ImageWorkshop. In order to init a new image, I need to call:
$layer = ImageWorkshop::initFromPath(__DIR__.'/../path/to/myimage.jpg');
I'd like to inject ImageWorkshop as a dependency, but I can't figure out how to do this since it uses static methods. I know I could just call ImageWorkshop statically from my service, but I'm trying to declare my dependencies.
That's the perfect use case for service factories.
You declare your $layer as a service and create it with the static factory method in the service container.
services:
myimage_layer:
class: PHPImageWorkshop\Core\ImageWorkshopLayer
factory_class: PHPImageWorkshop\ImageWorkshop
factory_method: initFromPath
arguments:
- "%kernel.root_dir%/../path/to/myimage.jpg"
Now you can inject the myimage_layer service into your service as a service argument.
EDIT: If you need the ImageWorkshop directly to call them, but don't want to write ImageWorkshop::initFromPath('...') directly in your code, you can decouple it with the class name. It's not really useful, because ImageWorkshop is not directly replaceable, but it helps for mocking in tests.
services:
myimage_whatever:
class: Acme\Bundle\AcmeBundle\Image\Whatever
arguments:
- "PHPImageWorkshop\\ImageWorkshop"
Your service:
namespace Acme\Bundle\AcmeBundle\Image;
class Whatever
{
private $imageWorkshop;
public function __construct($imageWorkshop)
{
$this->imageWorkshop = $imageWorkshop;
}
public function doWhatever($path)
{
$layer = $this->imageWorkshop::initFromPath($path);
// ...
}
}
Beware yourself, $imageWorkshop is no instance. Instead it's a string containing the fully qualified class name of ImageWorkshop to call the static method on it. I hope this should work.
Reference for calling a static method on a string variable containing the class name: http://php.net/manual/en/language.oop5.static.php#example-214
I would create a wrapper class and implement the static class methods in it
e.g
Class ImageWorkshopWrapper
{
public function initFromPath($path)
{
ImageWorkshop::initFromPath($path);
}
}
and inject ImageWorkshopWrapper class