spring boot + junit + overriden component instance - java

I've got sample project here. I'd like to setup som junit test with class com.github.bilak.axonframework.poc.command.user.UserTest
When I run test, I can see in log
Skipping bean definition for [BeanMethod:name=userCommandHandler,declaringClass=com.github.bilak.axonframework.poc.command.config.CommandConfiguration]: a definition for bean 'userCommandHandler' already exists. This top-level bean definition is considered as an override.
And then I can see that when UserRepository is injected to UserCommandHandler that's another instance as that which is used in UserTest class. Why this is done and how can I avoid this?
Thanks

It's because a bean of name userCommandHandler is defined twice in context. First as an annotated component com.github.bilak.axonframework.poc.command.user.UserCommandHandler registered with component scan, second as a bean defined in CommandConfiguration (line 75).
And then I can see that when UserRepository is injected to UserCommandHandler that's another instance as that which is used in UserTest class.
Looking at the GivenWhenThenTestFixture implementation I can see that it actually wraps the passed instance into some adapter. Moreover, because what you passes is actually a spring proxy which has the userRepository direct reference null (that's correct I believe), the effective registered handler has it also null, so you are probably experiencing null pointer exception because of that. If I change the setUp for your test:
#Before
public void setup() throws Exception {
fixture = Fixtures.newGivenWhenThenFixture(User.class);
UserCommandHandler target = (UserCommandHandler) ((Advised) userCommandHandler).getTargetSource().getTarget();
fixture.registerAnnotatedCommandHandler(target);
}
It helps.

Related

Spring Test with dependency Injection of real objects and mocks

I have a test use case in which based on a boolean property we decide which one of 2 Spring Beans to create upon application startup.
For simplicity, let's call them ProfileServiceA and ProfileServiceB.
When the boolean property is set to false (the default) it creates ProfileServiceA and when it's true it creates ProfileServiceB.
This is done inside of a configuration class annotated with #Configuration.
My test is pretty simple, I want to verify which one of the Beans is loaded in the Spring Context when our application is starting based on that property.
For each of those Beans, when we create them, the constructor gets multiple objects in order to be instantiated.
Most of the objects I have annotated with the #MockBean because they are only being pointed to in the constructor like we usually do with Dependency Injection and that's not a problem for me.
One of those properties is not only pointed at in the constructor but is actually being used to build one of the fields.
in the constructor of ProfileService we do something like this:
this.url = securityProperties.getProfile().getProtocol() + "://" + securityProperties.getProfile().getHost() + ":" + securityProperties.getProfile().getPort() + "/" + securityProperties.getProfile().getEndpoint();
The SecurityProperties class has the inner static class Profile, So when the application context starts to load and this Bean is being instantiated in the constructor (even before the method annotated with #Before) I fail on NullPointerException because the object Profile is still null (The SecurityProperties is not because it's annotated with #MockBean).
The SecurityProperties and its inner static class Profile are not defined as Beans but still, I tried to set the Profile object inside of the test class to be also #MockBean or #Mock but this didn't solve the issue.
I figured that I probably need to inject "real" Objects into the context but I couldn't find a wiki/docs on how to inject "real" objects WITH Mocked ones to an Autowired Spring Bean.
The SecurityProperties is not a Spring Bean but a regular data object (POJO).
You can implement the BeanPostProcessor interface in your test code. In the implementation of postProcessBeforeInitialization, if the current bean name is securityProperties (or whatever name your SecurityProperties bean has) then mock the behavior of SecurityProperties::getProfile() to return an actual Profile instance to avoid the NPE.
This works because ProfileService depends on SecurityProperties so the latter will be initiated first and right after that your postProcessBeforeInitialization will be called, right before the instantiation of ProfileService

How to fix NullPointerException on Autowired JdbcTemplate

I am re-writing my question to hopefully make more sense and get some help.
I have a Controller, 2 ClassRepository, and 2 Service classes (one of which is not annotated with #Service as I get an error when I annotate it, so instead I just use it as a class)
The class not annotated with #Service I simply pass the rateRepository object from the annotated Service to the unannotated service.
If I execute the following code in my annotated service
String zone = rateRepository.getPurolatorZone(request.getShipToZip().substring(0,3));
it works great.
however in my unannotated class where i instantiate the class
InternationalRateService internationalRateService = new InternationalRateService(this.rateRepository);
UPDATE:
I annotated my InternationalRateService class with #Service and decided to autowire the repository itself, and I still get a null pointer exception on the getPurolatorZone method.. I dont understand why it works in one service but not the other when they are set up the same.
Second Update:
as it turns out, im an idiot because i didn't even think to check that it was possible that the string i pass to the repository was what was actually throwing the error. Turns out I never set the local shiptozip variable so. yea im an idiot .
Spring will inject dependencies only in spring managed beans. If you create an object with new then it's not spring managed bean.
In your case, object of InternationalRateService is not managed, as you created by new operator.
So, inject InternationalRateService in your controller, so that all dependencies are injected

How can I inject property source of a bean in test

I am writing unit tests for my services in Spring, Java. I mock all dependencies in a tested class and I instantiate the tested class in a constructor, to which I pass mocked classes. The problem is that the tested class injects properties from .properties file into fields that are inside it (let's say Strings).
I use the standard combination of #PropertySource on a class level and #Value on a field level inside my tested class.
As we know, properties injection fails when class is instantiated through constructor (not as a bean during the Spring Container initialization). How do you deal with such problem?
I've got one solution, though I think it is bad and unsatisfactory, that is:
1. to #Autowire the class under test normally, then replace all its dependencies by using a setter.
I also know about the #TestPropertySource annotation and if I understand correctly, it does not provide a solution and it is only a way to override already existent properties - which is not the case, as we cannot really use any properties.
Thanks for help in advance :)
It is rather straight : in your unit test, inject the property in a String field and create the object under test not in the constructor of the test class but in the hook method invoked after the container has loaded the Spring context.
In JUnit 4, you specify this hook method with #Before and in JUnit 5 with #BeforeEach.
It would give something like :
#RunWith(SpringJUnit4ClassRunner.class)
public class FooTest{
Foo foo;
#Value("${myProp}")
String myProp;
#BeforeEach
public void beforeEach(){
foo = new Foo(myProp);
}
}
Note that to make your test be executed faster you should load from the Spring context only what your test requires : the environment part.

New bean is injected even when not calling getBean from spring context

I have a bean declared in by config file as:
#Bean
#Lazy
#Scope("prototype")
public SomeClass someClass()
{
return new SomeClass();
}
Then inside my test class I have the following code:
#Autowired
private SomeClass someClass;
#Before
public void setUp()
{
xyzObject.someMethod(someClass);
}
My question here is inside my setUp() method I am just referencing the autowired SomeClass bean but not getting it from the spring context using getBean(), but still it is creating a new bean everytime the setUp() is running before a test. Why is this happening? Does prototype scope means a new bean gets created whenever the bean's reference is used anywhere in the code? I haven't seen anything specified like that in the documentation.
That is the essence of Inversion of Control. Because you injected it into another bean, every time you instantiate another bean your injected bean would be created and provided by spring as part of instantiation of your containing bean. You don't need to call getBean() here. However if in some place you just need an instance of your SomeClass bean you may call getBean() to tell your spring environment to give you that bean to you. However, It is better to avoid such practice and rely on injection. Or create a Factory that can provide you such Bean (Still relaying on spring though) That would make your code not aware of Spring which is IMHO is more ellegant

compile time weaving and autowired on constructor

#Configurable
public TestClass(){
#Autowired SomeOtherClass otherClass;
public TestClass(Var1 var){
System.out.println(otherClass);
}
}
I using compile time weaving and call new testClass(var). i using dependency injection on the constructor like above "otherClass". It printed out 'null'. From my test, dependency injection 'otherClass' cannot be initialized in constructor. what should i do to allow dependency injection on "constructor" ?
Look at the Note in this section of the Spring documentation.
It shows you the #Configurable attribute to use to force the injection before the code within the constructor.
#Configurable(preConstruction=true)
Adding that attribute to your code above will stop the System.out.println(otherClass); from being null.
In support of the answer by Ralph.
From the Spring Autowired documentation.
Fields are injected right after construction of a bean, before any config methods are invoked.
HTH
I guess (but don't know 100%) that the Autowirering take place after the object is created. (I mean I know it for normal Spring Beans, for normal classes, but not 100% for #Configurable)
This mean you can not expect to have an Autowired field allready populated when the object is created.
You can check this if you add an second method printStats that is invoked after creation.
public class TestClass {
...
public void printStats(){
System.out.println(otherClass);
}
}
...
new TestClass(var).printStats();

Categories