1. 소개

이 기사에서는 JBehave간략히 살펴본 다음 BDD 관점에서 REST API를 테스트하는 데 중점을 둡니다.

2. JBehave와 BDD

JBehave는 행동 기반 개발 프레임 워크입니다. 자동화 된 승인 테스트를위한 직관적이고 접근 가능한 방법을 제공하려고합니다.

BDD에 익숙하지 않다면 이 기사 부터 시작 하여 일반적인 BDD 구조와 기능을 소개하는 또 다른 BDD 테스트 프레임 워크 인 Cucumber를 다루는 것이 좋습니다 .

다른 BDD 프레임 워크와 마찬가지로 JBehave는 다음 개념을 채택합니다.

  • 스토리 – 자동으로 실행 가능한 비즈니스 기능 증가를 나타내며 하나 이상의 시나리오로 구성됩니다.
  • 시나리오 – 시스템 동작의 구체적인 예를 나타냅니다.
  • 단계 – 기존 BDD 키워드를 사용하여 실제 행동을 나타냅니다 : Given , When , Then

일반적인 시나리오는 다음과 같습니다.

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

시나리오의 각 단계는 JBehave의 어노테이션에 해당합니다.

  • @Given : 컨텍스트 시작
  • @When : 행동을
  • @Then : 예상 결과 테스트

3. Maven 의존성

Maven 프로젝트에서 JBehave를 사용하려면 jbehave-core 의존성이 pom에 포함되어야합니다 .

<dependency>
    <groupId>org.jbehave</groupId>
    <artifactId>jbehave-core</artifactId>
    <version>4.1</version>
    <scope>test</scope>
</dependency>

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<String> storyPaths() {
        return Arrays.asList("increase.story");
    }

}

에서 storyPaths () , 우리는 우리의 제공 .story JBehave를 구문 분석 할 파일 경로를. 실제 단계 구현은 stepsFactory ()에 제공됩니다 . 그런 다음 configuration () 에서 스토리 로더 및 스토리 보고서가 올바르게 구성됩니다.

이제 모든 준비가 완료 되었으므로 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 a step is pending (단계가 보류 중일 때)가 표시되므로 @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를 사용하여 테스트하는 방법을 살펴 보겠습니다. 테스트는 Java로 REST API를 테스트하는 방법을 논의한 이전 기사를 기반으로합니다 .

이 기사에서는 GitHub REST API를 테스트했으며 주로 HTTP 응답 코드, 헤더 및 페이로드에 중점을 두었습니다. 간단하게하기 위해 우리는 각각 3 개의 개별 스토리로 작성할 수 있습니다.

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 = "https://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 = "https://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 = "https://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를 간략하게 소개하고 BDD 스타일 REST API 테스트를 구현했습니다.

일반 Java 테스트 코드와 비교할 때 JBehave로 구현 된 코드는 훨씬 명확하고 직관적이며 테스트 결과 보고서는 훨씬 더 우아해 보입니다.

항상 그렇듯이 예제 코드는 Github 프로젝트 에서 찾을 수 있습니다 .