Testen von REST mit mehreren MIME-Typen

Testen von REST mit mehreren MIME-Typen

1. Überblick

Dieser Artikel konzentriert sich auf das Testen eines REST-Service mit mehreren Medientypen / Darstellungen.

Wir werden Integrationstests schreiben, die in der Lage sind, zwischen den verschiedenen Arten von Repräsentationen zu wechseln, die von der API unterstützt werden. Das Ziel ist es, in der Lage zu sein, den exakt gleichen Test unter Verwendung der exakt gleichen URIs des Dienstes auszuführen und lediglich nach einem anderen Medientyp zu fragen.

2. Tore

Jede REST-API muss ihre Ressourcen als Repräsentationen mit einem oder mehreren Medientypen verfügbar machen. The client will set the Accept header to choose the type of representation it asks for from the service.

Da die Ressource mehrere Darstellungen haben kann, muss der Server einen Mechanismus implementieren, der für die Auswahl der richtigen Darstellung verantwortlich ist. Dies wird auch als Inhaltsverhandlung bezeichnet.

Wenn der Client nachapplication/xml fragt, sollte er eine XML-Darstellung der Ressource erhalten. Und wenn es nachapplication/json fragt, sollte es JSON bekommen.

3. Infrastruktur testen

Zunächst definieren wir eine einfache Schnittstelle für einen Marshaller. Dies ist die Hauptabstraktion, mit der der Test zwischen verschiedenen Medientypen wechseln kann:

public interface IMarshaller {
    ...
    String getMime();
}

Dann brauchen wir eine Möglichkeit, den richtigen Marshaller basierend auf einer externen Konfiguration zu initialisieren.

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

@Component
@Profile("test")
public class TestMarshallerFactory implements FactoryBean {

    @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 getObjectType() {
        return IMarshaller.class;
    }

    public boolean isSingleton() {
        return true;
    }
}

Schauen wir uns das an:

  • Zunächst wird hier die in Spring 3.1 eingeführte neue Abstraktion vonEnvironmentverwendet. Weitere Informationen hierzu finden Sie unterdetailed article on using Properties with Spring

  • Wir rufen dietest.mime-Eigenschaft aus der Umgebung ab und bestimmen damit, welcher Marshaller erstellt werden soll - hier funktioniert die Syntax von Java 7switch on String

  • Als Nächstes wird der Standard-Marshaller, falls die Eigenschaft überhaupt nicht definiert ist, der Jackson-Marshaller für die JSON-Unterstützung sein

  • Schließlich ist diesesBeanFactory nur in einem Testszenario aktiv, da wir die Unterstützung für@Profileverwenden, die ebenfalls in Spring 3.1 eingeführt wurde

Das war's - der Mechanismus kann zwischen Marshallern wechseln, basierend auf dem Wert der Eigenschafttest.mime.

4. Die JSON- und XML-Marshaller

In Zukunft benötigen wir die eigentliche Marshaller-Implementierung - eine für jeden unterstützten Medientyp.

Für JSON verwenden wirJackson als zugrunde liegende Bibliothek:

public class JacksonMarshaller implements IMarshaller {
    private ObjectMapper objectMapper;

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

    ...

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

Für die XML-Unterstützung verwendet der MarshallerXStream:

public class XStreamMarshaller implements IMarshaller {
    private XStream xstream;

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

    ...

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

Note that these marshallers are not Spring beans themselves. Der Grund dafür ist, dass sie vonTestMarshallerFactory; in den Spring-Kontext gebootet werden. Es ist nicht erforderlich, sie direkt zu Komponenten zu machen.

5. Konsumieren des Dienstes mit JSON und XML

Zu diesem Zeitpunkt sollten wir in der Lage sein, einen vollständigen Integrationstest für den bereitgestellten Service durchzuführen. Die Verwendung des Marshallers ist unkompliziert: Wir injizieren einIMarshaller in den Test:

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

    @Autowired
    private IMarshaller marshaller;

    // tests
    ...

}

Spring entscheidet anhand des Werts der Eigenschafttest.mime, welcher Marshaller genau injiziert werden soll.

Wenn wir für diese Eigenschaft keinen Wert angeben, greifen dieTestMarshallerFactory einfach auf den Standard-Marshaller zurück - den JSON-Marshaller.

6. Maven und Jenkins

Wenn Maven so eingerichtet ist, dass Integrationstests für einen bereits implementierten REST-Service ausgeführt werden, können wir ihn folgendermaßen ausführen:

mvn test -Dtest.mime=xml

Wenn dies der Fall ist, verwendet der Build dieintegration-test-Phase des Maven-Lebenszyklus:

mvn integration-test -Dtest.mime=xml

Weitere Informationen zum Einrichten des Maven-Builds zum Ausführen von Integrationstests finden Sie im ArtikelIntegration Testing with Maven.

Bei Jenkins müssen wir den Job konfigurieren mit:

This build is parametrized

Und dieString parameter:test.mime=xml hinzugefügt. **

Eine gängige Jenkins-Konfiguration müsste Jobs mit denselben Integrationstests für den implementierten Service ausführen - einer mit XML und der andere mit JSON-Repräsentationen.

7. Fazit

Dieser Artikel zeigte, wie eine REST-API getestet wird, die mit mehreren Darstellungen funktioniert. Die meisten APIs veröffentlichen ihre Ressourcen unter mehreren Repräsentationen. Daher ist das Testen all dieser Ressourcen von entscheidender Bedeutung. Die Tatsache, dass wir für alle genau dieselben Tests verwenden können, ist einfach cool.

Die vollständige Implementierung dieses Mechanismus - unter Verwendung tatsächlicher Integrationstests und Überprüfung der XML- und JSON-Darstellungen - finden Sie inthe GitHub project.