0

My question is similar to this one.

Setting: I have a GreetingResource which has a Autowired GreetingService to handle GET requests:

@Path("greetings")
public class GreetingResource 
{

@Autowired
private GreetingService service;

@GET
@Produces(MediaType.TEXT_PLAIN_VALUE)
public String getHello()
{
    try
    {
        return service.greet("world");
    }
    catch(SQLException e)
    {
        System.out.println("Request failed (500)");
        e.printStackTrace();
        return null;
    }
}
}

Problem: In my unit test I get org.springframework.beans.factory.NoSuchBeanDefinitionException:

No qualifying bean of type 'demo.rest.jersey.spring.GreetingService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1466)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1097)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1059)
    at org.glassfish.jersey.server.spring.AutowiredInjectResolver.getBeanFromSpringContext(AutowiredInjectResolver.java:104)
    at org.glassfish.jersey.server.spring.AutowiredInjectResolver.resolve(AutowiredInjectResolver.java:96)

Unit test class: In order to unit test this I have a testContext.xml which acts as application context for unit tests. It creates just one bean, namely the TestConfig:

@Configuration
public class TestConfig 
{
    @Bean
    @Primary
    public GreetingService greetingService() throws SQLException
    {
        GreetingService service = Mockito.mock(GreetingService.class);
        when(service.greet(anyString())).thenReturn("Hello");
        return service;
    }
}

The testContext.xml should be loaded by the unit test and hence the correct beans created:

public class Test_GreetingResource extends JerseyTest 
{
    @Override
    protected TestContainerFactory getTestContainerFactory() 
    {
        return new GrizzlyWebTestContainerFactory();
    }

    @Override
    protected DeploymentContext configureDeployment(){
        return ServletDeploymentContext
                .forServlet(new ServletContainer(new TestApp()))
                .addListener(ContextLoaderListener.class)
                .contextParam("contextConfigLocation", "classpath:testContext.xml")
                .build();
    }

    @Test
    public void doTest() throws SQLException
    {
        String response = target("greetings").request().get(String.class);
        assertEquals("response incorrect", "Hello", response);
        System.out.println(response);
    }
}

Notes: The TestApp simply registers the GreetingResource

public class TestApp extends ResourceConfig 
{
    public TestApp()
    {
        register(GreetingResource.class);
        packages("demo.rest.jersey.spring");
    }
}

Here is also the testContext.xml that I mentioned above:

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

    <bean id="testConfig" class="demo.rest.jersey.spring.TestConfig"></bean>
</beans>

Additional question: If the GreetingService mock is created as a bean, can I somehow alter the mock behaviour? I.e. right now I specify in the TestConfig what response the mock should give but I might want to alter that behaviour from test to test.

Thanks for the help!

tenticon
  • 2,639
  • 4
  • 32
  • 76

1 Answers1

0

I followed this answer and injected the GreetingService into the constructor of GreetingResource.

Then it's just

public class Test_GreetingResource extends JerseyTest
{
    @Mock
    private GreetingService service;

    @Override
    public ResourceConfig configure() 
    {
        MockitoAnnotations.initMocks(this);
        return new ResourceConfig()
            .register(new GreetingResource(service));
    }

    @Test
    public void testMockedGreetingService() 
    {
        try {
            when(service.greet(anyString())).thenReturn("Hello there");
        } catch (SQLException e) {
            fail("service cannot greet");
        }

        Response response = target("greetings")
                .request(MediaType.TEXT_PLAIN).get();

        String msg = response.readEntity(String.class);
        System.out.println("Message: " + msg);

        response.close();
    }
}
tenticon
  • 2,639
  • 4
  • 32
  • 76