1. 概述
本文将专注于测试支持多种媒体类型/表示的REST服务。
我们将编写能够切换到API支持的不同类型表示的集成测试。目标是在请求服务的相同URI时,只需更改媒体类型,就能运行完全相同的测试。
2. 目标
任何REST API都需要使用一种或多种媒体类型来展示其资源。客户端会在请求中设置Accept
头,以从服务中选择它所要求的表示形式。
由于资源可以有多种表示形式,服务器需要实现一个负责选择正确表示的机制。这通常被称为内容协商。
因此,如果客户端请求application/xml
,则应获取资源的XML表示。如果请求application/json
,则应获取JSON表示。
3. 测试基础设施
首先,我们定义一个简单的 Marshaller 接口。这个接口将是测试切换不同媒体类型的主抽象:
public interface IMarshaller {
...
String getMime();
}
然后我们需要一种方法根据某种外部配置初始化正确的 Marshaller。
为此,我们将使用Spring的FactoryBean
来初始化 Marshaller,并使用一个简单的属性来确定使用哪个 Marshaller:
@Component
@Profile("test")
public class TestMarshallerFactory implements FactoryBean<IMarshaller> {
@Autowired
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();
default:
throw new IllegalStateException();
}
}
return new JacksonMarshaller();
}
public Class<IMarshaller> getObjectType() {
return IMarshaller.class;
}
public boolean isSingleton() {
return true;
}
}
让我们来看一下:
- 使用了Spring 3.1中引入的新
Environment
抽象——有关如何使用Properties与Spring的详细信息,请参阅在Spring 3.1中使用Properties。 - 我们从环境环境中获取
test.mime
属性,并使用它来确定创建哪个 Marshaller——这里使用了Java 7的字符串开关语法。 - 如果该属性未定义,那么默认 Marshaller 将是用于JSON支持的Jackson Marshaller。
- 最后,这个
BeanFactory
只在测试场景中活动,因为我们使用了Spring 3.1中引入的@Profile
支持。
就这样,机制可以根据test.mime
属性的值切换 Marshaller。
4. JSON和XML Marshaller
接下来,我们需要实际的 Marshaller 实现,每个支持的媒体类型一个。
对于JSON,我们将使用Jackson
作为底层库:
public class JacksonMarshaller implements IMarshaller {
private ObjectMapper objectMapper;
public JacksonMarshaller() {
super();
objectMapper = new ObjectMapper();
}
...
@Override
public String getMime() {
return MediaType.APPLICATION_JSON.toString();
}
}
对于XML支持,Marshaller使用XStream
:
public class XStreamMarshaller implements IMarshaller {
private XStream xstream;
public XStreamMarshaller() {
super();
xstream = new XStream();
}
...
public String getMime() {
return MediaType.APPLICATION_XML.toString();
}
}
请注意,这些Marshaller本身并不是Spring bean。原因是它们将由TestMarshallerFactory
注入到Spring上下文中,无需直接使其成为组件。
5. 使用JSON和XML消费服务
此时,我们应该能够对部署的服务运行完整的集成测试。使用Marshaller非常简单:我们将IMarshaller
注入到测试中:
@ActiveProfiles({ "test" })
public abstract class SomeRestLiveTest {
@Autowired
private IMarshaller marshaller;
// tests
...
}
Spring会根据test.mime
属性的值决定注入哪个确切的Marshaller。
如果我们不提供这个属性的值,TestMarshallerFactory
将简单地回退到默认的Marshaller——JSON Marshaller。
6. Maven和Jenkins
如果Maven设置为针对已部署的REST服务运行集成测试,那么我们可以使用以下命令运行:
mvn test -Dtest.mime=xml
或者,如果构建使用Maven生命周期的integration-test
阶段:
mvn integration-test -Dtest.mime=xml
有关如何设置Maven构建以运行集成测试的更多详细信息,请参阅使用Maven Cargo插件进行集成测试文章。
在Jenkins中,我们必须配置工作流,如下所示:
This build is parametrized
并添加一个String参数
:test.mime=xml
。
常见的Jenkins配置是运行针对部署服务的同一套集成测试——一个使用XML表示,另一个使用JSON表示。
7. 总结
本文展示了如何测试一个支持多种表示形式的REST API。大多数API确实会在多个表示下发布其资源,因此测试所有这些表示至关重要。而且,我们可以在所有这些表示上使用相同的测试,这一点很酷。
这个机制的实际实现——使用实际的集成测试并验证XML和JSON表示——可以在GitHub项目中找到。