Тестване на REST API с JBehave

1. Въведение

В тази статия ще разгледаме бързо JBehave, след което ще се съсредоточим върху тестване на REST API от гледна точка на BDD.

2. JBehave и BDD

JBehave е рамка за развитие, управлявана от поведението. Той възнамерява да осигури интуитивен и достъпен начин за автоматизирано тестване за приемане.

Ако не сте запознати с BDD, добре е да започнете с тази статия, обхващаща друга рамка за тестване на BDD - Cucumber, в която представяме общата структура и характеристики на BDD.

Подобно на други BDD рамки, JBehave възприема следните концепции:

  • Story - представлява автоматично изпълним прираст на бизнес функционалност, включва един или повече сценарии
  • Сценарии - представляват конкретни примери за поведението на системата
  • Стъпки - представете действителното поведение, използвайки класически ключови думи BDD: Дадено , кога и тогава

Типичен сценарий би бил:

Given a precondition When an event occurs Then the outcome should be captured

Всяка стъпка в сценария съответства на анотация в JBehave:

  • @Given : иницииране на контекста
  • @ Кога : направете действието
  • @ След това : тествайте очаквания резултат

3. Зависимост на Maven

За да използваме JBehave в нашия проект maven, зависимостта jbehave-core трябва да бъде включена в pom :

 org.jbehave jbehave-core 4.1 test 

4. Бърз пример

За да използваме JBehave, трябва да следваме следните стъпки:

  1. Напишете потребителска история
  2. Сравнете стъпките от потребителската история с Java кода
  3. Конфигурирайте потребителски истории
  4. Изпълнете тестове JBehave
  5. Преглед на резултатите

4.1. История

Нека започнем със следната проста история: „като потребител искам да увелича брояч, за да мога да увелича стойността на брояча с 1“.

Можем да дефинираме историята във файл .story :

Scenario: when a user increases a counter, its value is increased by 1 Given a counter And the counter has any integral value When the user increases the counter Then the value of the counter must be 1 greater than previous value

4.2. Стъпки за картографиране

Предвид стъпките, нека внедрим това в Java:

public class IncreaseSteps { private int counter; private int previousValue; @Given("a counter") public void aCounter() { } @Given("the counter has any integral value") public void counterHasAnyIntegralValue() { counter = new Random().nextInt(); previousValue = counter; } @When("the user increases the counter") public void increasesTheCounter() { counter++; } @Then("the value of the counter must be 1 greater than previous value") public void theValueOfTheCounterMustBe1Greater() { assertTrue(1 == counter - previousValue); } }

Не забравяйте, че стойността в поясненията трябва точно да съответства на описанието .

4.3. Конфигуриране на нашата история

За да изпълним стъпките, трябва да подготвим сцената за нашата история:

public class IncreaseStoryLiveTest extends JUnitStories { @Override public Configuration configuration() { return new MostUsefulConfiguration() .useStoryLoader(new LoadFromClasspath(this.getClass())) .useStoryReporterBuilder(new StoryReporterBuilder() .withCodeLocation(codeLocationFromClass(this.getClass())) .withFormats(CONSOLE)); } @Override public InjectableStepsFactory stepsFactory() { return new InstanceStepsFactory(configuration(), new IncreaseSteps()); } @Override protected List storyPaths() { return Arrays.asList("increase.story"); } }

В storyPaths () ние предоставяме нашия .story файлов път, който да бъде анализиран от JBehave. Реалното изпълнение на стъпки е предоставено в stepsFactory () . След това в конфигурацията () , устройството за зареждане на истории и докладът за историята са правилно конфигурирани.

Сега, когато имаме всичко готово, можем да започнем нашата история просто като стартираме: mvn clean test .

4.4. Преглед на резултатите от теста

Можем да видим резултата от теста си в конзолата. Тъй като нашите тестове преминаха успешно, изходът ще бъде същият с нашата история:

Scenario: when a user increases a counter, its value is increased by 1 Given a counter And the counter has any integral value When the user increases the counter Then the value of the counter must be 1 greater than previous value

Ако забравим да приложим някоя стъпка от сценария, докладът ще ни уведоми. Кажете, че не сме внедрили стъпката @When :

Scenario: when a user increases a counter, its value is increased by 1 Given a counter And the counter has any integral value When the user increases the counter (PENDING) Then the value of the counter must be 1 greater than previous value (NOT PERFORMED)
@When("the user increases the counter") @Pending public void whenTheUserIncreasesTheCounter() { // PENDING }

В доклада се казва, че @When стъпка е в очакване и поради това стъпката @Then няма да бъде изпълнена.

Ами ако нашата стъпка @Then се провали? Можем да забележим грешката веднага от отчета:

Scenario: when a user increases a counter, its value is increased by 1 Given a counter And the counter has any integral value When the user increases the counter Then the value of the counter must be 1 greater than previous value (FAILED) (java.lang.AssertionError)

5. Тестване на REST API

Сега разбрахме основите на JBhave ; ще видим как да тестваме REST API с него. Нашите тестове ще се основават на предишната ни статия, обсъждаща как да тестваме REST API с Java.

В тази статия тествахме API на GitHub REST и се фокусирахме главно върху HTTP кода за отговор, заглавките и полезния товар. За простота можем да ги запишем съответно в три отделни истории.

5.1. Тестване на кода на състоянието

Историята:

Scenario: when a user checks a non-existent user on github, github would respond 'not found' Given github user profile api And a random non-existent username When I look for the random user via the api Then github respond: 404 not found When I look for eugenp1 via the api Then github respond: 404 not found When I look for eugenp2 via the api Then github respond: 404 not found

Стъпките:

public class GithubUserNotFoundSteps { private String api; private String nonExistentUser; private int githubResponseCode; @Given("github user profile api") public void givenGithubUserProfileApi() { api = "//api.github.com/users/%s"; } @Given("a random non-existent username") public void givenANonexistentUsername() { nonExistentUser = randomAlphabetic(8); } @When("I look for the random user via the api") public void whenILookForTheUserViaTheApi() throws IOException { githubResponseCode = getGithubUserProfile(api, nonExistentUser) .getStatusLine() .getStatusCode(); } @When("I look for $user via the api") public void whenILookForSomeNonExistentUserViaTheApi( String user) throws IOException { githubResponseCode = getGithubUserProfile(api, user) .getStatusLine() .getStatusCode(); } @Then("github respond: 404 not found") public void thenGithubRespond404NotFound() { assertTrue(SC_NOT_FOUND == githubResponseCode); } //... }

Забележете как при изпълнението на стъпките използвахме функцията за инжектиране на параметри . Аргументите, извлечени от кандидата за стъпка, просто се съчетават, следвайки естествения ред на параметрите в анотирания Java метод.

Също така се поддържат анотирани поименни параметри:

@When("I look for $username via the api") public void whenILookForSomeNonExistentUserViaTheApi( @Named("username") String user) throws IOException

5.2. Тестване на типа носител

Ето една проста история за тестване на MIME тип:

Scenario: when a user checks a valid user's profile on github, github would respond json data Given github user profile api And a valid username When I look for the user via the api Then github respond data of type json

И ето стъпките:

public class GithubUserResponseMediaTypeSteps { private String api; private String validUser; private String mediaType; @Given("github user profile api") public void givenGithubUserProfileApi() { api = "//api.github.com/users/%s"; } @Given("a valid username") public void givenAValidUsername() { validUser = "eugenp"; } @When("I look for the user via the api") public void whenILookForTheUserViaTheApi() throws IOException { mediaType = ContentType .getOrDefault(getGithubUserProfile(api, validUser).getEntity()) .getMimeType(); } @Then("github respond data of type json") public void thenGithubRespondDataOfTypeJson() { assertEquals("application/json", mediaType); } }

5.3. Тестване на полезния товар на JSON

Тогава последната история:

Scenario: when a user checks a valid user's profile on github, github's response json should include a login payload with the same username Given github user profile api When I look for eugenp via the api Then github's response contains a 'login' payload same as eugenp

И изпълнението на обикновените прави стъпки:

public class GithubUserResponsePayloadSteps { private String api; private GitHubUser resource; @Given("github user profile api") public void givenGithubUserProfileApi() { api = "//api.github.com/users/%s"; } @When("I look for $user via the api") public void whenILookForEugenpViaTheApi(String user) throws IOException { HttpResponse httpResponse = getGithubUserProfile(api, user); resource = RetrieveUtil.retrieveResourceFromResponse(httpResponse, GitHubUser.class); } @Then("github's response contains a 'login' payload same as $username") public void thenGithubsResponseContainsAloginPayloadSameAsEugenp(String username) { assertThat(username, Matchers.is(resource.getLogin())); } }

6. Обобщение

В тази статия представихме накратко JBehave и внедрихме тестове за REST API в стил BDD.

В сравнение с нашия обикновен тестов код на Java, кодът, реализиран с JBehave, изглежда много ясен и интуитивен, а отчетът за резултатите от теста изглежда много по-елегантен.

Както винаги, примерният код може да бъде намерен в проекта Github.