Robert Johnson
Robert Johnson

Reputation: 662

Spring integration testing - transaction declaration in config seems to break test

I am playing around with a Spring MVC + Hibernate + MySQL "Hello World" app, and am currently trying run the following integration test on a Spring MVC controller using jUnit.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"file:src/main/webapp/WEB-INF/springapp-servlet.xml"})
public class InventoryControllerIT
{
    @Autowired
    private InventoryController controller;

    @Test
    public void handleRequest_anyRequest_returnsSuccessfully() throws Exception
    {       
        ModelAndView modelAndView = this.controller.handleRequest(null, null);
    }
}

However, every time I do so I get the following exception:

org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [springapp.web.InventoryController] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency.

Previously I hadn't implemented any real data access and the test passed fine, but now that I have added a Hibernate implementation of my DAO along with spring transaction management I get this error. Here are the relevant parts of my applet context configuration 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:p="http://www.springframework.org/schema/p"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/tx
                           http://www.springframework.org/schema/tx/spring-tx.xsd">


    <bean name="/hello.htm" class="springapp.web.InventoryController">
        <property name="productManager" ref="productManager" />
        <property name="productDao" ref="productDao" />
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>


    ...


    <!-- Hibernate -->
    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">

        <property name="dataSource">
            <ref bean="dataSource" />
        </property>

        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
                <prop key="hibernate.show_sql">true</prop>
            </props>
        </property>

        <property name="mappingJarLocations">
            <list>
                <value>WEB-INF/lib/springapp-dataaccess*.jar</value>
            </list>
        </property>
    </bean>

    <bean id="productDao" class="springapp.dataaccess.dao.ProductHibernateDao">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <tx:annotation-driven />

    <bean id="transactionManager"
        class="org.springframework.orm.hibernate4.HibernateTransactionManager"
        p:sessionFactory-ref="sessionFactory" />

</beans>

If I remove the <tx:annotation-driven /> from the config then the above exception does not occur, but then the test fails because the data access call that occurs in the handler no longer has an open transaction. The app runs just fine outside of the test. Anyone have any ideas as to what the issue is?

Upvotes: 0

Views: 679

Answers (2)

asa
asa

Reputation: 4040

I had a similar issues while running the unit tests of a small library I was building.

replace your :

<tx:annotation-driven />

with

<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>

Note that on my project I also had to add the following dependency (maven project) for the unit tests:

    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>2.2.2</version>
        <scope>test</scope>
    </dependency>

Best regards.

Upvotes: 0

axtavt
axtavt

Reputation: 242686

When InventoryController implements any interfaces Spring by default applies transactional aspect to it using interface-based proxy. Such a proxy implements interfaces of InventoryController, but it's not a subclass of InventoryController, therefore it cannot be injected into a field of type InventoryController.

You either need to use interface as a type of the field to be autowired, or configure Spring to apply target-class-based proxy instead.

See also:

Upvotes: 1

Related Questions