1. 概述
本文將重點介紹如何測試具有多種媒體類型/表示形式的 REST 服務。
我們將編寫能夠在多種表示形式之間切換的集成測試,這些表示形式由 API 支持。目標是能夠運行相同的測試,消耗相同的 URI,但請求不同的媒體類型。
2. 目標
任何 REST API 都需要通過一種或多種媒體類型來暴露其資源表示形式。 客户端將通過設置 Accept 標頭來選擇它從服務中請求的表示形式類型。
由於資源可以有多種表示形式,因此服務器必須實現一個負責選擇正確表示形式的機制。 這也稱為內容協商。
因此,如果客户端請求 application/xml,則應收到資源的 XML 表示形式。 如果它請求 application/json,則應收到 JSON。
3. 測試基礎設施
我們將首先定義一個簡單的接口,用於marshaller。這將是主要的抽象,允許測試在不同的Media Type之間切換:
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 的詳細文章
- 我們從環境中檢索 test.mime 屬性,並使用它來確定要創建的marshaller——這裏使用了 Java 7 的 switch on String 語法
- 接下來,如果屬性未定義,則默認marshaller將是用於 JSON 支持的 Jackson marshaller
- 最後——這個 BeanFactory 僅在測試場景中處於活動狀態,因為我們使用了在 Spring 3.1 中引入的 @Profile 支持
這就是全部——該機制能夠根據 test.mime 屬性的值之間切換marshaller。
4. JSON 和 XML 轉換器
接下來,我們需要實際的轉換器實現——針對每種支持的媒體類型一個。
對於 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 beans。原因在於它們將被 TestMarshallerFactory 通過 bootstrap 注入到 Spring 上下文中,因此無需直接將其聲明為組件。
5. 使用 JSON 和 XML 消費服務
此時,我們應該能夠對部署的服務進行完整的集成測試。 使用marshaller 相當簡單:我們將IMarshaller 注入到測試中:
@ActiveProfiles({ "test" })
public abstract class SomeRestLiveTest {
@Autowired
private IMarshaller marshaller;
// tests
...
}Spring 將根據 test.mime 屬性的值確定要注入的精確marshaller。
如果未為該屬性提供值,TestMarshallerFactory 將簡單地回退到默認marshaller——JSONmarshaller。
6. Maven 和 Jenkins
如果 Maven 配置為在已部署的 REST 服務上運行集成測試,則可以使用以下命令執行:
mvn test -Dtest.mime=xml如果構建使用 Maven 生命週期中的 integration-test 階段:
mvn integration-test -Dtest.mime=xml為了更詳細地瞭解如何設置 Maven 構建以運行集成測試,請參閲《Maven 集成測試》文章。
使用 Jenkins 時,我們需要配置工作項如下:
This build is parametrized並且添加了 字符串參數: test.mime=xml。
一個常見的 Jenkins 配置是讓多個作業運行相同的集成測試,這些測試針對部署的服務 – 一個使用 XML 格式,另一個使用 JSON 格式。
7. 結論
本文介紹瞭如何測試能夠同時支持多種表示形式的 REST API。 大多數 API 都將資源發佈在多種表示形式下,因此測試所有這些表示形式至關重要。 能夠使用相同的測試在所有這些表示形式上運行,這本身就非常酷。