Spring Beans - Spring finds two beans instead of one

Viewed 444

I am trying to do something here with Spring and TestNG. Pretty new to both, and just copy-pasting some code from here and there to try to make a new feature in an existing codebase.

Pretty much the gist is like this:

I have my source code. I need a bean in there, so in my Spring XML configuration file, I do:

<bean id="bean1" class="com.mypackage.MyClass" />

Then I have my code in MyClass.java where I go and do:

@Autowired
@Qualifier("bean1")
private MyClass myBean;

public void myCallingFunction(final MyInput input) {
    myBean.myFunction(input.getList().get(0));
}

I have my test code as follows:

@Autowired
@Qualifier("getMyBean")
private MyClass myBean;

@Autowired
@Qualifier("MyBean")
private MyClass myBean2;

@Test(expectedExceptions = ValidationException.class)
public void testExceptionCase() throws ValidationException {
    List<String> list = new ArrayList<>();
    list.add("SomeString");

    MyInput input = new MyInput();
    input.setList(list);

    context.checking(new Expectations() {
        {
            oneOf(myBean).myFunction(with(any(String.class)));
            will(throwException(new ValidationException()));
        }
    });

    myBean2.myCallingFunction(input);
    context.assertIsSatisfied();
}

And a 'test' bean like:

    @Bean
    public MyClass getMyClass() {
        return context.mock(MyClass.class);
    }

When I'm running this test now, I get the below:

not all expectations were satisfied
[testng] expectations:
[testng]   expected once, never invoked: myBean.myFunction(ANYTHING); throws <com.mypackage.ValidationException>
[testng]    at org.jmock.Mockery.assertIsSatisfied(Mockery.java:196)
[testng]    at com.mypackage.test.testExceptionCase(MyFileTest.java:51)
[testng]    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[testng]    at java.lang.reflect.Method.invoke(Method.java:498)
[testng]    at org.springframework.test.context.testng.AbstractTestNGSpringContextTests.run(AbstractTestNGSpringContextTests.java:175)
[testng]    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
[testng]    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
[testng]    at java.lang.Thread.run(Thread.java:748)

I need two beans. One 'mocked', one not mocked. How can I make this work?

EDIT: I totally messed up the naming here. Was being hasty. I'll edit this question with proper names.

1 Answers

You currently have three beans of type MyClass in your context. In your test you actually wire the beans named getMyBean and MyBean using the @Qualifier annotation. Your test bean has the name getMyClass. So you actually add a third one instead of overriding the getMyBean bean.

To achieve the desired behaviour define your test bean like this:

@Bean(name="getMyBean")
public MyClass mockedMyClass() {
    return context.mock(MyClass.class);
}

Now it overrides the bean definition of your "productive" bean getMyBean with the mocked one.

EDIT: I just saw that you have five beans. I missed bean1 and the xml config bean named QuarantineHelper. Honestly, you should give your classes, objects and variables better names. Even when you just ask a question. It is really hard not getting confused.

So you have five beans. And there is no bean with the names defined you want to inject in the production and test code. I have no idea how your spring context can be loaded with this configuration. Did you configure TestNG to set up the spring context? Normally you extend AbstractTestNGSpringContextTests and provide a context configuration with @ContextConfiguration

Related