使用多种表述测试REST服务的小窍门

2023-03-07 16:24:24 浏览数 (1)

原文链接:https://www.baeldung.com/testing-rest-api-with-multiple-media-types

作者: Eugen Paraschiv

译者: helloworldtang

目录

  • 1. 概览
  • 2. 目标
  • 3. 测试基础设施
  • 4. JSON和XML Marshaller
  • 5. 使用JSON和XML来消费服务
  • 6. Maven和Jenkins
  • 7. 总结
名词释义:
  • 资源表述:在REST中的一切都被认为是一种资源,XML或JSON分别是两种不同的表述形式
  • Marshaller【在业界没有一个统一的中文词汇】:是字符串和对象进行互相转换的组件的统称,譬如,java中的XML Marshaller,可以将Java对象转换成xml,也可以将xml字符串转换为Java对象。

1. 概览

本文将着重于测试具有多种媒体类型/资源表述的REST服务。

我们将编写能够在API支持的多种资源表述之间切换的集成测试。具体目标是,即使更改了请求的媒体类型 ,也能够运行完全相同的测试,并且这个测试所消费服务的URI也不需要更改。

2. 目标

任何REST API都需要以某种媒体类型的表述来暴露其资源,在许多情况下,它不止一个。客户端通过设置Accept头来选择它从服务请求的资源表述类型。

因为资源可以有多种表述,所以服务器必须实现一个负责选择正确表述的机制——也称为内容协商。因此,如果客户端请求application/xml,那么它应该得到XML表述的资源,如果它请求application/json,那么它应该得到JSON。

3. 测试基础设施

首先,我们将为Marshaller定义一个简单的接口——这将是允许测试用例在不同媒体类型之间切换的主要抽象:

代码语言:javascript复制
public interface IMarshaller {
    ...
    String getMime();
}

然后,我们需要一种方法来根据某种形式的外部配置初始化正确的Marshaller。对于这种机制,我们将使用Spring FactoryBean来初始化Marshaller和一个简单的属性,以确定要使用哪个Marshaller

代码语言:javascript复制
@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——更多的介绍可以看这里:关于使用Spring Properties的详细文章。
  • test.mime属性是从Environment中检索出来的,用于确定要创建哪个Marshaller——在这里使用了Java 7 switch支持String的语法。
  • 接下来,设置默认Marshaller为Jackson Marshaller。如果没有定义属性,资源表述的媒体类型将会是JSON
  • 最后,这个BeanFactory只在这个测试场景中生效,因为使用了Spring 3.1中引入了的新特性@Profile。

就是这样——这个机制能够根据test.mime属性值来切换Marshaller

4. JSON和XML Marshaller

继续,我们将需要实际的Marshaller实现——针对每种受支持的媒体类型。

对于JSON,我们将使用Jackson作为底层库:

代码语言:javascript复制
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:

代码语言:javascript复制
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直接注入到测试用例中:

代码语言:javascript复制
@ActiveProfiles({ "test" })
public abstract class SomeRestLiveTest {

    @Autowired
    private IMarshaller marshaller;

    // tests
    ...

}

在Spring中注入精确的Marshaller当然是由test.mime属性值决定的;这可以从属性文件中获取,也可以手动配置在测试环境中。如果这个属性没有提供一个值,那么TestMarshallerFactory就会简单地回到默认的Marshaller——JSON marshaller。

6. Maven和Jenkins

如果Maven被配置为针对已经部署的REST服务运行集成测试,那么它可以像这样运行:

代码语言:javascript复制
mvn test -Dtest.mime=xml

或者,如果这个构建使用Maven生命周期的integration-test阶段:

代码语言:javascript复制
mvn integration-test -Dtest.mime=xml

有关如何使用这些阶段以及如何配置Maven构建的更多细节,以便将应用程序部署绑定到pre-integration-test目标,在集成测试目标中运行集成测试,然后在post-integration-test中关闭已部署的服务,参见 使用Maven进行集成测试

对于Jenkins来说,Maven任务必须配置为:

代码语言:javascript复制
This build is parametrized

并且,需要新增这个字符串参数: test.mime=xml.

一个常见的Jenkins配置将不得不使用与已部署的服务运行相同的集成测试集——一个带有XML,另一个带有JSON表述。

7. 总结

本文展示了如何测试一个具有多重表述的REST API。大多数API都在多个表述中发布它们的资源,因此测试所有这些都是至关重要的;事实上,我们可以在所有这些测试中使用完全相同的测试,这是很酷的。

所有这些示例和代码片段都可以在GitHub上找到。这是一个基于Eclipse的项目,所以它应该很容易导入和运行。

0 人点赞