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支持的Jacksonmarshaller
- 最後——這個BeanFactory僅在測試場景中處於活動狀態,因為我們使用了@Profile支持,該支持也引入於Spring 3.1
這就是它——該機制能夠根據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 支持,轉換器使用 XStream:
public class XStreamMarshaller implements IMarshaller {
private XStream xstream;
public XStreamMarshaller() {
super();
xstream = new XStream();
}
...
public String getMime() {
return MediaType.APPLICATION_XML.toString();
}
}
請注意,這些轉換器本身不是 Spring Bean。 原因是它們將在 TestMarshallerFactory 中進行啓動,因此無需直接將其聲明為組件。
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,必須使用以下配置:
此構建已參數化
以及添加的 字符串參數: test.mime=xml。
一種常見的 Jenkins 配置是讓多個工作項運行相同的集成測試套件,這些測試套件針對已部署的服務,一個使用 XML,另一個使用 JSON 表示。
7. 結論
本文介紹瞭如何測試能夠同時支持多種表示形式的 REST API。 大多數 API 會發布其資源在多種表示形式下,因此測試所有這些表示形式至關重要。 能夠使用相同的測試在所有這些表示形式下,這真是太酷了。