Välkommen till Callista Enterprise blogg - här finns tekniska artiklar, presentationer och nyheter om arkitektur och systemutveckling. Håll dig uppdaterad genom att följa oss på Twitter.
Callista Enterprise medarbetare Johan Kindgren

SoapUI, Gradle och mockade webtjänster

// Johan Kindgren

SoapUI är ett verktyg som ofta används vid utveckling av system där man anropar webtjänster (både Soap och Rest). Dels så kan man skapa testsviter för att verifiera en befintlig tjänst, eller så kan man simulera/mocka tjänster som man ska anropa i sitt system.

Det finns stora möjligheter att anpassa det data som den mockade tjänsten ska returnera och även lägga till kontroller på att de inkommande anropen ser rätt ut. Exakt hur man skapar sina mockade tjänster tas inte upp i denna blog-post, men finns beskrivet på Soap Mocking, getting started.

Vid utveckling kör man SoapUI lokalt i sin utvecklingsmiljlö och det innebär oftast att man startar SoapUI, högerklickar på sina mockade tjänster och väljer att starta dem. Om man nu istället tänker sig att man vill driftsätta sin applikation, så att t ex kravställare kan verifiera att vi har uppfattat kraven på rätt sätt, hur kör man då sina mockade tjänster? Som tur är har utvecklarna bakom SoapUI tänkt på detta och implementerat en möjlighet att exportera sina mockade tjänster som ett War-arkiv, vilket sedan enkelt kan driftsättas på valfri (java) webserver. Exempel på hur det ser ut när en mockad tjänst anropas: Webgränssnitt

För att exportera de mockade tjänsterna högerklickar man på sitt projekt och väljer sedan Deploy as War, vilket öppnar ett dialogfönster där man kan konfigurera vad som ska exporteras. Det är en ganska enkel operation, men trots allt ett manuellt steg som ska göras. Med en manuell process finns alltid möjligheter till fel, som vi helst vill undvika! Vad gör vi då?

Ett första steg till automatisering skulle kunna vara att köra det script wargenerator.sh som finns i SoapUI-installationen i samband med att man bygger sitt system. Detta kräver dock att SoapUI finns installerat hos samtliga utvecklare och även på byggservern. Kan vi åstadkomma något bättre/enklare?

Visst kan man det! Smartbear har publicerat binärerna för SoapUI på ett maven-repository, vilket gör att man kan ange dessa som ett beroende för ett Gradle-bygge. Dock går det inte bara att ange ett beroende till SoapUI och starta, man måste placera jar-filerna i en struktur som ser likadan ut som en SoapUI-installation. När man väl har dessa på plats kan man köra ett JavaExec-task, och då få samma export-funktionalitet som scriptet.

Därefter är det dags att sätta upp de parametrar som används för att skapa war-filen. Enklaste sättet att få fram alla parametrar är att köra scriptet utan argument: wargenerator.sh

Efter att ha studerat dokumentationen ingående (läs trial-n-error) så hittade jag en kombination som ger önskat resultat och producerar en war-fil. Med ytterligare lite mer konfiguration av Gradle-bygget så läggs denna war-fil till som en artefakt från modulen och kan då användas från andra delar i projektet. I exempel-koden har jag lagt till möjligheten att starta en webserver (Jetty), så att man på ett enkelt sätt kan titta på resultatet och provköra sina mockade tjänster.

configurations {
    soapui {
        resolutionStrategy {
            dependencySubstitution {
                substitute module('javax.jms:jms') with module('javax.jms:jms-api:1.1-rev-1')
            }
        }
    }
    war
}

dependencies {
    soapui(group: 'com.smartbear.soapui', name: 'soapui', version: '5.3.0')
}

task copyDependencies(type: Copy) {

    def filesToCopy = copySpec {
        from configurations.soapui
    }

    into buildDir

    into("lib") {
        exclude "soapui-*.jar"
        with filesToCopy
    }
    into("soapui") {
        include "soapui-*.jar"
        with filesToCopy
    }
}

task createWar(type: JavaExec, group: 'build') {
    dependsOn copyDependencies

    inputs.file file('SoapUI-War-soapui-project.xml')

    systemProperties = ["soapui.home": "$buildDir/soapui",
                        "user.home": projectDir]

    classpath = configurations.soapui

    main = 'com.eviware.soapui.tools.SoapUIMockAsWarGenerator'

    args "-d", "$buildDir/war", "-f", "$buildDir/soapuimocks.war", "-w", "true", "-s", "none.xml", file('SoapUI-War-soapui-project.xml')

    ext.destFile = file("$buildDir/soapuimocks.war")

    outputs.file destFile
}

Ett sista steg för att köra sina mockade tjänster skulle kunna vara att lägga till war-filen i en docker-container som sedan körs i lämplig testmiljö.

Starta SoapUI

Förutom möjligheten att producera en war-fil med mockade tjänster ger en sådan här lösning även möjligheten att köra SoapUI direkt från gradle-scriptet och därmed garantera att hela teamet använder exakt samma version av SoapUI, utan att behöva installera det lokalt. För att få detta att fungera bra får man ändra variabeln user.home så att den pekar på aktuell projekt-katalog och på så sätt kunna lagra de filer som annars skulle lagras lokalt för varje användare. För att inte få absoluta sökvägar i sina projektfiler är det viktigt att man uppdaterar inställningar för både workspace och projekt, där man behöver sätta Project root till ${workspaceDir} samt Resource root till ${projectDir}. Har man gjort dessa ändringar så kan man lägga in både sin workspace- och projekt-fil i versionshantering.

task runSoapUi(type: JavaExec, group: 'run') {
    dependsOn copyDependencies

    inputs.file file('SoapUI-War-soapui-project.xml')

    systemProperties = ["soapui.home": "$buildDir/soapui",
                        "user.home"  : projectDir]

    classpath = configurations.soapui

    main = 'com.eviware.soapui.SoapUI'
}

Koden för detta exempel finns publicerat på Github https://github.com/callistaenterprise/blog-soapui-war

Det visade sig att man behöver ange user.home även när man startar Jetty-servern i exempel-projektet, annars kommer man att få en del felmeddelanden som beror på att SoapUI hittar ett antal plugins under användarens “riktiga” hem-katalog.

Tack för att du läser Callista Enterprise blogg.
Hjälp oss att nå ut med information genom att dela nyheter och artiklar i ditt nätverk.

Kommentarer