Ravi Nain
Ravi Nain

Reputation: 655

ReflectionTestUtils not working with @Autowired in Spring Test

I am trying to add mock object in CourseServiceImpl's courseDao field but it is not working.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
    locations = {"file:src/main/webapp/WEB-INF/config/servlet-config.xml"}
)
@ActiveProfiles("test")
public final class CourseServiceTest {
  @Mock
  private CourseDao courseDao;
  @Autowired
  private CourseService courseService;
  @Before
  public void setUp() {
    MockitoAnnotations.initMocks(this);
  }

@Test
  public void testCourseServiceNotNull() {
    assertNotNull(courseService);
    assertNotNull(courseDao);
    ReflectionTestUtils.setField(courseService, "courseDao", courseDao, CourseDao.class);
  }

The reflection statement throws an error that field "courseDao" didn't found. But, when I create an object using new operator then it works fine.

ReflectionTestUtils.setField(new CourseServiceImpl(), "courseDao", courseDao, CourseDao.class);

servlet-config.xml

<mvc:annotation-driven />
<mvc:resources location="pdfs" mapping="/pdfs/**" />

<security:global-method-security
    pre-post-annotations="enabled" />

<bean
    class="org.springframework.web.servlet.view.InternalResourceViewResolver"
    p:prefix="/WEB-INF/view/" p:suffix=".jsp" p:order="2" />

<bean
    class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"
    p:contentNegotiationManager-ref="contentNegId" p:defaultViews-ref="defaultViewList"
    p:order="1" />

<bean id="contentNegId"
    class="org.springframework.web.accept.ContentNegotiationManager">
    <constructor-arg>
        <bean
            class="org.springframework.web.accept.PathExtensionContentNegotiationStrategy">
            <constructor-arg>
                <map>
                    <entry key="json" value="application/json" />
                    <entry key="xml" value="application/xml" />
                </map>
            </constructor-arg>
        </bean>
    </constructor-arg>
</bean>

<util:list id="defaultViewList">
    <bean
        class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" />
    <bean class="org.springframework.web.servlet.view.xml.MarshallingView">
        <constructor-arg>
            <bean class="org.springframework.oxm.xstream.XStreamMarshaller"
                p:autodetectAnnotations="true" />
        </constructor-arg>
    </bean>
</util:list>

<bean class="org.springframework.web.servlet.view.BeanNameViewResolver"
    p:order="0" />

<bean id="localeResolver"
    class="org.springframework.web.servlet.i18n.SessionLocaleResolver"
    p:defaultLocale="en" />

<bean id="messageSource"
    class="org.springframework.context.support.ResourceBundleMessageSource"
    p:basename="messages" />

<context:property-placeholder location="classpath:messages.properties" />

<import resource="/hibernate-config.xml" />
<import resource="/hibernate-config-test.xml" />

hibernate-config-test.xml

<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close" p:driverClassName="com.mysql.jdbc.Driver"
        p:url="jdbc:mysql://localhost:3306/school-repo-test" p:username="user"
        p:password="password" />


    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"
        p:dataSource-ref="myDataSource" p:hibernateProperties-ref="hibernateProps"
        p:annotatedClasses-ref="mapClasses">
    </bean>

    <util:list id="mapClasses">
        <value>org.school.model.Course</value>
        <value>org.school.model.Role</value>
        <value>org.school.model.Staff</value>
        <value>org.school.model.Student</value>
        <value>org.school.model.Subject</value>
    </util:list>

    <util:properties id="hibernateProps">
        <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
        <prop key="hibernate.hbm2ddl.auto">update</prop>
        <prop key="hibernate.show_sql">true</prop>
    </util:properties>

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

Apart from profile name, rest is same for hibernate-config file.

CourseServiceImpl

@Service(value = "courseService")
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public class CourseServiceImpl implements CourseService {
  @Autowired
  private MessageSource messageSource;
  @Autowired
  private CourseDao courseDao;
  @Autowired
  private ApplicationContext context;

Please advise.

Upvotes: 4

Views: 6208

Answers (1)

Sergey Bespalov
Sergey Bespalov

Reputation: 1766

Your CourseServiceImpl class has @Transactional annotation which means that bean instance wrapped with "Transactional" proxy before it injected as dependency in CourseServiceTest and all other beans in Spring context. Such proxy instance hides all the private fields of original CourseServiceImpl instance.

So you cannot access fields you want because injected courseService instance is not the original CourseServiceImpl class any more, it is dynamic cglib or JDK proxy class.

Upvotes: 2

Related Questions