4

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.

Ravi Nain
  • 605
  • 8
  • 16

1 Answers1

2

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.

Sergey Bespalov
  • 1,746
  • 1
  • 12
  • 29
  • [this](http://stackoverflow.com/a/34477414/6825250) solution can be used in your case. – Sergey Bespalov Oct 12 '16 at 02:43
  • Thanks for your reply. So, when I create instance using new operator then it won't wrapped with `"Transactional"` proxy, is this correct? If yes, do we usually test the service layer by creating instance using new operator? – Ravi Nain Oct 12 '16 at 02:47
  • >>> "So, when I create instance using new operator then it won't wrapped with "Transactional" proxy, is this correct?" Yes >>>" If yes, do we usually test the service layer by creating instance using new operator?" No. In case of Spring services must be injected, like it already done in your Test. – Sergey Bespalov Oct 12 '16 at 02:51
  • Thanks @Sergey for your reply. – Ravi Nain Oct 12 '16 at 03:44
  • @RaviNain you got the answer to your question? – Sergey Bespalov Oct 12 '16 at 03:54
  • Yes, got it. It works how I wanted it to. Thanks again! – Ravi Nain Oct 12 '16 at 04:26