Skip to content

@Capturing not always able to mock objects. #161

@brianruss

Description

@brianruss

I have encountered an issue when using @capturing. It is related to Spring,Apache CXF, the version of JMockit and also the sequence of running tests.
The issue is very obscure, but I have a concise set of files available that is a full maven project that demonstrates the problem. I have tried to put these at the end of the issue, but can send these if needed.

The business model is:
An interface ITestObject - Containes a single method that helps to identify when the problem arises.
A class TestObjectContainer - A java bean that has a single property of type ITestObject
A class TestObject that implements ITestOject

The testing performed is:
FirstTest - A Junit test class with a single test method that simply loads a spring XML context file first-test.xml and closes the context
SecondTest - A Junit test class with a single test method that

  • Has @capturing on ITestObject types
  • loads spring XML context file second-test.xml
  • Gets a named bean from the context of type TestObjectContainer
  • Checks that the contained ITestObject bean is mocked.

The environment is:
Windows 7
Java 8
JUnit 4.12
Spring 4.1.6 Release
JMockit - 1.6 or 1.16 (we had been using 1.6 and tried 1.16 when problems arose)
CXF 3.0.4
Eclipse Luna

Setup A

  • JMockit 1.6 (This was the version we were using when we first encountered the problem.
  • The first-test.xml configuration has a TestObjectContainer bean containing an ITestObject that is actually a CXF proxy client for a web service.
  • The second-test.xml configuration also has a TestObjectContainer bean containing an ITestObject that is actually a CXF proxy client for a web service.

Scenario A1

Run SecondTest on its own - PASS - confirms the ITestObject is mocked.

Scenario A2

Run FirstTest then SecondTest as a single execution (I selected the package to run) in eclipse (It is hard to know what order eclipse/junit will run the tests) - SecondTest FAILs - it is attempting to connect with the CXF client proxy.

Setup B

As setup A, but instead of first-test.xml having a CXF client proxy, it has a POJO of type TestObject

Scenario B1

Run FirstTest then SecondTest as a single execution in eclipse -PASS

Setup C

  • JMockit 1.16
  • The second-test.xml configuration has a TestObjectContainer bean containing an ITestObject that is actually a CXF proxy client for a web service.

Scenario C1

Run SecondTest on its own - FAIL (This passes on JMockit 1.6)

Setup D

  • JMockit 1.16
  • The second-test.xml configuration has a TestObjectContainer bean containing an ITestObject that has a POJO of type TestObject.

Scenario D1

Run SecondTest on its own - PASS

So, trying to summarise the factors involved:

  • Using a CXF bean rather than a POJO causes failure (Scenarios A2 -> B1 and C1 -> D1)
  • Running tests in isolation or as part of a set of tests causes failure (A1 -> A2)
  • Using the latest JMockit can cause a failure (A1 -> D1)

Apologies for the length of post and amount of detail, but hopefully will aid diagnosis.

Many thanks,

Brian.

Files

src/main/java/com/example/ITestObject.java

package com.example;
import javax.jws.WebService;

@WebService
public interface ITestObject 
{
    public boolean isMocked();
}

src/main/java/com/example/TestObject.java

package com.example;

import org.apache.log4j.Logger;

public class TestObject implements ITestObject
{
    private static final Logger log = Logger.getLogger(TestObject.class);

    public boolean isMocked()
    {
        log.info("In Real impl");
        return false;
    }
}

src/main/java/com/example/TestObjectContainer.java

package com.example;

public class TestObjectContainer 
{
    private ITestObject testObject;

    public ITestObject getTestObject()
    {
        return testObject;
    }
    public void setTestObject(ITestObject testObject)
    {
        this.testObject = testObject;
    }
}

src/test/java/com/example/FirstTest.java

package com.example;

import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class FirstTest 
{
    @Test
    public void test1()
    {
        String configFileName = "/first-test.xml";
        ClassPathXmlApplicationContext configContext = new ClassPathXmlApplicationContext(configFileName);
        configContext.close();
      }
}

src/test/java/com/example/SecondTest.java

package com.example;

import mockit.Capturing;
import mockit.NonStrictExpectations;

import org.junit.Assert;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SecondTest 
{
     @Capturing
    ITestObject mockObject;
    @Test
    public void secondTest() throws Exception
    {
        new NonStrictExpectations()
        {{
            mockObject.isMocked(); result= true;
        }};

        String configFileName = "/second-test.xml";
        ClassPathXmlApplicationContext configContext = new ClassPathXmlApplicationContext(configFileName);

        Assert.assertTrue("Direct access to mock is not working",mockObject.isMocked());


        TestObjectContainer springBeanObject = configContext.getBean("secondTestContainer",TestObjectContainer.class);
        Assert.assertTrue("Spring bean access to mock is not working",springBeanObject.getTestObject().isMocked());

        configContext.close();
    }
}

src/test/resources/first-test.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jaxws="http://cxf.apache.org/jaxws"

    xsi:schemaLocation=
    "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd         
    http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
        ">


    <bean name="firstTestContainer" class="com.example.TestObjectContainer">
        <property name="testObject" >

            <!-- Choose either the jaxws bean, or the POJO bean -->
            <jaxws:client 
                id="test-object-1"
                serviceClass="com.example.ITestObject"
                address="http://nohost1/path" />

<!--             <bean class="com.example.TestObject" /> -->

        </property>
    </bean>
</beans>

src/test/resources/second-test.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jaxws="http://cxf.apache.org/jaxws"

    xsi:schemaLocation=
    "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd         
    http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
        ">


    <bean name="secondTestContainer" class="com.example.TestObjectContainer">
        <property name="testObject" >

            <jaxws:client 
                id="test-object-2"
                serviceClass="com.example.ITestObject"
                address="http://nohost2/path" />

<!--             <bean class="com.example.TestObject" /> -->
        </property>
    </bean>
</beans>

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">



    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>repo</artifactId>
    <packaging>jar</packaging>
    <version>0.0.1-SNAPSHOT</version>
    <name>Mocking issue repo</name>
    <url />


    <properties>
        <spring.version>4.1.6.RELEASE</spring.version>
        <cxf.version>3.0.4</cxf.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>com.googlecode.jmockit</groupId>
            <artifactId>jmockit</artifactId>
            <version>1.6</version>
            <scope>test</scope>
        </dependency>

<!--         <dependency> -->
<!--             <groupId>org.jmockit</groupId> -->
<!--             <artifactId>jmockit</artifactId> -->
<!--             <version>1.16</version> -->
<!--             <scope>test</scope> -->
<!--         </dependency>       -->

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxws</artifactId>
            <version>${cxf.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http</artifactId>
            <version>${cxf.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>


    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.1</version>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                    </configuration>
            </plugin>
        </plugins>
    </build>

</project>

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions