Testing REST with multiple MIME types – 用多种MIME类型测试REST

最后修改: 2013年 1月 18日


1. Overview


This article will focus on testing a REST Service with multiple Media Types/representations.


We will write integration tests capable of switching between the multiple types of Representations supported by the API. The goal is to be able to run the exact same test consuming the exact same URIs of the service, just asking for a different Media Type.


2. Goals


Any REST API needs to expose its Resources as representations using one or more Media Types. The client will set the Accept header to choose the type of representation it asks for from the service.

任何REST API都需要使用一种或多种媒体类型将其资源作为表示方法公开。客户端将设置Accept头,以选择它向服务请求的表示类型。

Since the Resource can have multiple representations, the server will have to implement a mechanism responsible for choosing the right representation. This is also known as Content Negotiation.

由于资源可以有多种表现形式,服务器将必须实现一种机制,负责选择正确的表现形式。这也被称为 “内容协商”。

Thus, if the client asks for application/xml, then it should get an XML representation of the Resource. And if it asks for application/json, then it should get JSON.


3. Testing Infrastructure


We’ll begin by defining a simple interface for a marshaller. This will be the main abstraction that will allow the test to switch between different Media Types:


public interface IMarshaller {
    String getMime();

Then we need a way to initialize the right marshaller based on some form of external configuration.


For this, we’ll use a Spring FactoryBean to initialize the marshaller and a simple property to determine which marshaller to use:


public class TestMarshallerFactory implements FactoryBean<IMarshaller> {

    private Environment env;

    public IMarshaller getObject() {
        String testMime = env.getProperty("test.mime");
        if (testMime != null) {
            switch (testMime) {
            case "json":
                return new JacksonMarshaller();
            case "xml":
                return new XStreamMarshaller();
                throw new IllegalStateException();

        return new JacksonMarshaller();

    public Class<IMarshaller> getObjectType() {
        return IMarshaller.class;

    public boolean isSingleton() {
        return true;

Let’s look at this:


  • first, the new Environment abstraction introduced in Spring 3.1 is used here – for more on this check out the detailed article on using Properties with Spring
  • we retrieve the test.mime property from the environment and use it to determine which marshaller to create – some Java 7 switch on String syntax at work here
  • next, the default marshaller, in case the property isn’t defined at all, is going to be the Jackson marshaller for JSON support
  • finally – this BeanFactory is only active in a test scenario, as we’re using the @Profile support, also introduced in Spring 3.1

That’s it – the mechanism is able to switch between marshallers based on whatever the value of the test.mime property is.


4. The JSON and XML Marshallers


Moving on, we’ll need the actual marshaller implementation – one for each supported Media Type.


For JSON we’ll use Jackson as the underlying library:


public class JacksonMarshaller implements IMarshaller {
    private ObjectMapper objectMapper;

    public JacksonMarshaller() {
        objectMapper = new ObjectMapper();


    public String getMime() {
        return MediaType.APPLICATION_JSON.toString();

For the XML support, the marshaller uses XStream:


public class XStreamMarshaller implements IMarshaller {
    private XStream xstream;

    public XStreamMarshaller() {
        xstream = new XStream();


    public String getMime() {
        return MediaType.APPLICATION_XML.toString();

Note that these marshallers are not Spring beans themselves. The reason for that is they will be bootstrapped into the Spring context by the TestMarshallerFactory; there’s no need to make them components directly.

请注意,这些marshaller不是Spring Bean本身。原因是它们将被TestMarshallerFactory引导到Spring上下文中;没有必要让它们直接成为组件。

5. Consuming the Service With Both JSON and XML


At this point, we should be able to run a full integration test against the deployed service. Using the marshaller is straightforward: we’ll inject an IMarshaller into the test:

在这一点上,我们应该能够针对部署的服务运行一个完整的集成测试。使用marshaller很简单:我们将注入一个 IMarshaller到测试中。

@ActiveProfiles({ "test" })
public abstract class SomeRestLiveTest {

    private IMarshaller marshaller;

    // tests


Spring will decide the exact marshaller to inject based on the value of the test.mime property.


If we don’t provide a value for this property, the TestMarshallerFactory will simply fall back on the default marshaller – the JSON marshaller.

如果我们不为这个属性提供一个值,TestMarshallerFactory将简单地返回到默认的marshaller – JSON marshaller。

6. Maven and Jenkins


If Maven is set up to run integration tests against an already deployed REST Service, then we can run it using:


mvn test -Dtest.mime=xml

Or, if this the build uses the integration-test phase of the Maven lifecycle:


mvn integration-test -Dtest.mime=xml

For more details on how to set up the Maven build to run integration tests, see the Integration Testing with Maven article.


With Jenkins, we must configure the job with:


This build is parametrized

And the String parameter: test.mime=xml added.


A common Jenkins configuration would be having to jobs running the same set of integration tests against the deployed service – one with XML and the other with JSON representations.


7. Conclusion


This article showed how to test a REST API that works with multiple representations. Most APIs do publish their Resources under multiple Representations, so testing all of these is vital. The fact that we can use the exact same tests across all of them is just cool.

这篇文章展示了如何测试一个使用多种表现形式的REST API。大多数API确实在多个表示法下发布他们的资源,所以测试所有这些表示法是至关重要的。事实上,我们可以在它们之间使用完全相同的测试,这很酷。

The full implementation of this mechanism – using actual integration tests and verifying both the XML and JSON representations – can be found in the GitHub project.

该机制的完整实现–使用实际的集成测试并验证 XML 和 JSON 表示法–可以在GitHub 项目中找到。