44

Here are the files that I use:

component.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
         http://www.springframework.org/schema/context
         http://www.springframework.org/schema/context/spring-context-3.0.xsd 
         http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd">

    <context:component-scan
        base-package="controllers,services,dao,org.springframework.jndi" />
</beans>

ServiceImpl.java

@org.springframework.stereotype.Service
public class ServiceImpl implements MyService {

    @Autowired
    private MyDAO myDAO;

    public void getData() {...}    
}

ServiceImplTest.java

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath*:conf/components.xml")
public class ServiceImplTest{

    @Test
    public void testMyFunction() {...}
}

Error:

16:22:48.753 [main] ERROR o.s.test.context.TestContextManager - Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@2092dcdb] to prepare test instance [services.ServiceImplTest@9e1be92]
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'services.ServiceImplTest': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private services.ServiceImpl services.ServiceImplTest.publishedServiceImpl; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [services.ServiceImpl] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:287) ~[spring-beans.jar:3.1.2.RELEASE]
Premraj
  • 72,055
  • 26
  • 237
  • 180
  • 1. Your context configuration mentions `components.xml`, but your file is called `Componet.xml` (Could just be typos in this post) 2. There are no beans defined in your Component.xml for the `PublishedReferenceYieldDAO` class – Dan Temple Feb 19 '14 at 11:21
  • Also you specify component-scan twice. One in xml and one with an annotation. Only one of them is needed. – MystyxMac Feb 19 '14 at 11:32
  • @DanTemple typo in post.. actually my file name is component.xml – Premraj Feb 19 '14 at 11:38
  • @MystyxMac thanks for your answer, but still I am facing the same issue. – Premraj Feb 19 '14 at 11:39
  • See https://stackoverflow.com/questions/56712707 – tkruse Nov 04 '22 at 09:44

8 Answers8

25

Make sure you have imported the correct package. If I remeber correctly there are two different packages for Autowiring. Should be :org.springframework.beans.factory.annotation.Autowired;

Also this looks wierd to me :

@ContextConfiguration("classpath*:conf/components.xml")

Here is an example that works fine for me :

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/applicationContext_mock.xml" })
public class OwnerIntegrationTest {

    @Autowired
    OwnerService ownerService;

    @Before
    public void setup() {

        ownerService.cleanList();

    }

    @Test
    public void testOwners() {

        Owner owner = new Owner("Bengt", "Karlsson", "Ankavägen 3");
        owner = ownerService.createOwner(owner);
        assertEquals("Check firstName : ", "Bengt", owner.getFirstName());
        assertTrue("Check that Id exist: ", owner.getId() > 0);

        owner.setLastName("Larsson");
        ownerService.updateOwner(owner);
        owner = ownerService.getOwner(owner.getId());
        assertEquals("Name is changed", "Larsson", owner.getLastName());

    }
Sembrano
  • 1,127
  • 4
  • 18
  • 28
12

I've done it with two annotations for test class: @RunWith(SpringRunner.class) and @SpringBootTest. Example:

@RunWith(SpringRunner.class )
@SpringBootTest
public class ProtocolTransactionServiceTest {

    @Autowired
    private ProtocolTransactionService protocolTransactionService;
}

@SpringBootTest loads the whole context, which was OK in my case.

ognjenkl
  • 1,407
  • 15
  • 11
7

A JUnit4 test with Autowired and bean mocking (Mockito):

// JUnit starts with spring context
@RunWith(SpringRunner.class)
// spring loads context configuration from AppConfig class
@ContextConfiguration(classes = AppConfig.class)
// overriding some properties with test values if you need
@TestPropertySource(properties = {
        "spring.someConfigValue=your-test-value",
})
public class PersonServiceTest {

    @MockBean
    private PersonRepository repository;

    @Autowired
    private PersonService personService; // uses PersonRepository    

    @Test
    public void testSomething() {
        // using Mockito
        when(repository.findByName(any())).thenReturn(Collection.emptyList());
        Person person = new Person();
        person.setName(null);

        // when
        boolean found = personService.checkSomething(person);

        // then
        assertTrue(found, "Something is wrong");
    }
}

Sergey Nemchinov
  • 1,348
  • 15
  • 21
6

For Spring 5.x and JUnit 5, writing unit tests is quite different.

We have to use @ExtendWith to register Spring extensions (SpringExtension). This brings Spring into play which activates part of the application context (instantiates and manages beans from selected configuration classes).

Note that this is different from the effect of @SpringBootTest which loads the full application context (and IMHO cannot be considered a unit test).

For example, let's create a configuration class FooConfig which produces a bean named foo1:

@Configuration
public class FooConfig
{
    @Bean
    public String foo1() { return "Foo1"; }
}

Now, let's write a JUnit 5 test case which injects foo1:

import static org.junit.jupiter.api.Assertions.*;
// ... more imports ...

@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {
    helloworld.config.FooConfig.class,
})
class FooTests
{
    @BeforeAll
    static void setUpBeforeClass() throws Exception {}

    @AfterAll
    static void tearDownAfterClass() throws Exception {}

    @BeforeEach
    void setUp() throws Exception {}

    @AfterEach
    void tearDown() throws Exception {}
    
    @Autowired
    private String foo1;
    
    @Test
    void test()
    {
        assertNotNull(foo1);
        System.err.println(foo1);
    }
}
Michail Alexakis
  • 1,405
  • 15
  • 14
2

In Spring 2.1.5 at least, the XML file can be conveniently replaced by annotations. Piggy backing on @Sembrano's answer, I have this. "Look ma, no XML".

It appears I to had list all the classes I need @Autowired in the @ComponentScan

@RunWith(SpringJUnit4ClassRunner.class)
@ComponentScan(
    basePackageClasses = {
            OwnerService.class
            })
@EnableAutoConfiguration
public class OwnerIntegrationTest {
    
    @Autowired
    OwnerService ownerService;
    
    @Test
    public void testOwnerService() {
       Assert.assertNotNull(ownerService);
    }
}
Patrice Gagnon
  • 1,276
  • 14
  • 14
0

I think somewhere in your codebase are you @Autowiring the concrete class ServiceImpl where you should be autowiring it's interface (presumably MyService).

Premraj
  • 72,055
  • 26
  • 237
  • 180
jmkgreen
  • 1,633
  • 14
  • 22
  • Double check for any other instances and that the context actually looks for the package with the implementation class. It can be helpful in these cases to use log4j with Spring and switch on debugging for the org.springframework package hierarchy - you get to see what it is considering and then doing. – jmkgreen Feb 19 '14 at 11:56
0

You should make another XML-spring configuration file in your test resource folder or just copy the old one, it looks fine, but if you're trying to start a web context for testing a micro service, just put the following code as your master test class and inherits from that:

@WebAppConfiguration
@RunWith(SpringRunner.class)
@ContextConfiguration(locations = "classpath*:spring-test-config.xml")
public abstract class AbstractRestTest {
    @Autowired
    private WebApplicationContext wac;
}
0

You can use @Import annotation. It's more readable and shorter than using the @ComponentScan annotation.

import org.springframework.context.annotation.Import;

@Import(value = {MyService.class, MyInjectedService.class})
public class JUnitTest {
    @Autowired
    private MyService service;

    // ...
}
Marcus Voltolim
  • 413
  • 4
  • 12