Let's say I have Following classes:
public class A {
#Autowired B b;
public void doSomething(){
b.doSomeThingElse();
}
#Component
#Autowired C c;
public class B {
public void doSomethingElse(){
c.doIt();
}
How can I test A when you know I want to mock c.doIt() but want to call b.doSomethingElse(); with EasyMock?
Thanks in advance
#Autowired is nice but tend to make us forget about how to test. Just add a setter for b and c.
C c = mock(C.class);
c.doIt();
replay(c);
B b = new B();
b.setC(c);
A a = new A();
a.setB(b);
a.doSomething();
verify(c);
Or use constructor injection.
C c = mock(C.class);
c.doIt();
replay(c);
B b = new B(c);
A a = new A(b);
a.doSomething();
verify(c);
In this case, your classes become:
public class A {
private B b;
public A(B b) { // Spring will autowired by magic when calling the constructor
this.b = b;
}
public void doSomething() {
b.doSomeThingElse();
}
}
#Component
public class B {
private C c;
public B(C c) {
this.c = c;
}
public void doSomethingElse(){
c.doIt();
}
}
Related
I have a hierarchy of beans dependency of same parent class S as:
A -> B -> C
where Bean A contains bean B, bean B contains C with code structure something like this:
public class A extends S {
private S successor;
}
public class B extends S {
private S successor;
}
public class C extends S {
private S successor;
}
And when implementing I have
A a = new A();
B b = new B();
C c = new C();
a.successor = b;
b.successor = c;
What I really want to do here to set all the immediate above bean creation and dependency relationships in the Configuration instead of hardcoding in the code; something like:
#Configuration
public class MyConfig {
#Bean
public A a {
return new A();
}
#Bean
public B b {
B b = new B();
A a; // somehow get the bean A here
a.successor = b;
}
#Bean
public C c {
C c = new C();
B b; // somehow get the bean b here
b.successor = c;
}
}
Any inputs on how to go about this using Spring boot Dependency injection?
You can pass required beans as arguments to your provider methods.
#Bean
public A a() {
return new A();
}
#Bean
public B b(A a) {
B b = new B();
a.successor = b;
return b;
}
#Bean
public C c(B b) {
C c = new C();
b.successor = c;
return c;
}
However, this sets the a.successor only when B is injected somewhere. I believe this is not what you expect, and inverting the construction chain is desired:
#Bean
public A a(B b) {
A a = new A();
a.successor = b;
return a;
}
#Bean
public B b(C c) {
B b = new B();
b.successor = c;
return b;
}
#Bean
public C c() {
return new C();
}
Let's say I have classA and classB:
public class A {
private B b;
public A(String id){
this.b = new B(id);
}
public void doSomethingA(String id){
// do somethingA
}
}
public class B{
public B(String id){
// call anotherThing (id)
}
public void doSomethingB(){
//somethingB
}
}
now I want to test methods inside classA (with it's instance) but wanna mock classB
Mockito allows me to mock classB, but when I instantiate classA, the constructor calls classB (which I want to avoid)
Is there a way to mock only the constructor (either classA or classB) but not the other methods?
You may mock any B object but you don't want to.
You want to mock the B b field of the A class.
Which is different.
You have to refactor your design and do B instantiation a dependency and not an internal processing.
A simple way is passing directly the B variable instead of the String as parameter :
public class A {
private B b;
public A(B b){
this.b = b;
}
public void doSomethingA(String id){
// do somethingA
}
}
Now mocking is straight :
#Mock B b;
public void test(){
A a = new A(b);
}
An alternative way would be using a Function<String, B> .
public class A {
private B b;
public A(Function<String, B> bFunction, String id){
this.b = bFunction.apply(id);
}
public void doSomethingA(String id){
// do somethingA
}
}
Mocking becomes so :
#Mock B b;
public void test(){
A a = new A(s-> b, "anyValue");
}
And implementation code could instantiate A as :
A a = new A(B::new, "id");
I have two classes
Class B {
#Resource
C c;
}
Class A {
private final B b;
public A(B b) {
this.b = b;
}
}
Then class A is initialized using Spring through #Bean annotation as follows:
#Configuration
public class AppConfigHelper {
#Bean
public C getC() {
return new C();
}
#Bean
public B getB() {
return new B();
}
#Bean
public A getA() {
return new A(getB());
}
}
The problem that I end up with is C getting null in object of type B. Is there a solution to this problem?
I have to get A initialized this way only as the B is the old code which I do not want to touch at this point of time.
I've got circular dependency and java config. While resolving it with xml config is very easy I can't resolve it with java config without #Autowired. Beans:
public class A {
private B b;
public B getB() {
return b;
}
public void setB(B b) {
this.b = b;
}
}
public class B {
private A a;
public A getA() {
return a;
}
public void setA(A a) {
this.a = a;
}
}
I've tried this(I've read that with #Bean annotation Spring won't invoke method every time bean is referenced, but in this case it's actually been invoked all the time):
#Configuration
public class Config {
#Bean
public A a() {
A a = new A();
a.setB(b());
return a;
}
#Bean
public B b() {
B b = new B();
b.setA(a());
return b;
}
}
And this, with #Autowired of Configuration class fields:
#Configuration
public class Config {
#Autowired
A a;
#Autowired
B b;
#Bean
public A a() {
A a = new A();
a.setB(b);
return a;
}
#Bean
public B b() {
B b = new B();
b.setA(a);
return b;
}
}
Also I've tried all above with #Lazy annotation. Doesn't help. But works perfectly if I annotate setters of A and B with #Autowired. But it's not what I want right now. What am I doing wrong and is there any way to resolve Circular dependency in java config without usage of #Autowired?
The behavior you want to get is the following
A a = new A();
B b = new B();
a.setB(b);
b.setA(a);
#Bean methods don't give you that. They run to completion to provide a bean instance.
You basically have to partially create one of the instances, then finish initializing it when you've created the other.
#Configuration
class Config {
#Bean
public A a() {
A a = new A();
return a;
}
#Bean
public B b() {
B b = new B();
A a = a();
b.setA(a);
a.setB(b);
return b;
}
}
or
#Bean
public B b(A a) {
B b = new B();
b.setA(a);
a.setB(b);
return b;
}
Another approach using #Autowired and #Component is to use this pattern:
#Component
class A {
private B b;
public B getB() {
return b;
}
public void setB(final B b) {
this.b = b;
}
}
#Component
class B {
private final A a;
#Autowired
public B(final A a) {
this.a = a;
a.setB(this);
}
public A getA() {
return a;
}
}
This eliminates the need for a separate #Configuration-class. Furthermore, the setB-method can possibly be package-protected if the classes exist in the same package to minimize scoping as much as possible.
I want to add another possible solution for your code. Instead of setting circular dependencies right in the config:
#Configuration
public class Config {
#Bean
public A a() {
A a = new A();
a.setB(b());
return a;
}
#Bean
public B b() {
B b = new B();
b.setA(a());
return b;
}
}
You could also let the spring do the work with the power of #Autowired annotation.
#Configuration
public class Config {
#Bean
public A a() {
A a = new A();
return a;
}
#Bean
public B b() {
B b = new B();
return b;
}
}
public class A {
private B b;
#Autowired
public setB(B b) { this.b = b; }
}
public class B {
private A a;
#Autowired
public setA(A a) { this.a = a; }
}
Of course it is non trivial from the "clean/readable/understandable" point of view because now your configuration is mixed in #Configuration and class itself. But as circular dependencies are quite rare, we could afford the hack.
This is the controller which calls thread 'TestRunner'.
#Controller
#RequestMapping("/welcome")
public class HomeController {
#RequestMapping(method = RequestMethod.GET)
public ModelAndView addCustomerPage() throws Exception{
ModelAndView modelAndView = new ModelAndView("customer/add-customer-form");
A a = new A();
B b = new B();
C c = new C();
TestRunner runner = new TestRunner(a, b, c);
Thread t = new Thread(runner);
t.start();
return modelAndView;
}
}
This is my thread which calls service HomeService. This service is autowired but still I getting null pointer exception when I call homeService.testMeth(a,b,c);
#Controller
public class TestRunner implements Runnable{
private A a;
private B b;
private C c;
#Autowired
private HomeService homeService;
public TestRunner() {
super();
// TODO Auto-generated constructor stub
}
public TestRunner(A a, B b, C c){
this.a = a;
this.b = b;
this.c = c;
}
public void run() {
// TODO Auto-generated method stub
homeService.testMeth(a,b,c);
}
}
This is service class.
#Service
public class HomeService {
public void testMeth(A a, B b, C c){
System.out.println("inside....");
}
}
Is this because of I am creating 'TestRunner' object with 'new' ?
Is this because of I am creating 'TestRunner' object with 'new' ?
Yes, It is because of this you get NullpointerExceptoin.
To fix the issue change the following:
Mark the following three classes A, B, C as component - if not
already done. Ensure the package is in component scan path:
#Component
public class A {
#Component
public class B {
#Component
public class C {
Then Autowire the A, B, C instances in TestRunner. Also change the annotation of TestRunner to #Component
#Component
public class TestRunner implements Runnable{
#Autowired
private A a;
#Autowired
private B b;
#Autowired
private C c;
In HomeRunner create an instance field for TestRunner and autowire it. Remove the instansiation code with new operator for TestRunner.