RedditアプリのAPIをテストする

1概要

私たちはしばらくの間、 私たちの簡単なReddit App のREST APIを構築してきました - それは、真剣になって テストを始める 時です。

これで、/reddit-app-replace-reddit-auth-with-form-b​​ased-login[最終的に切り替えられました]が、より単純な認証メカニズムにリンクされました。これも同様に簡単です。これらすべてのライブテストには、https://code.google.com/p/rest-assured/[強力な rest-assured ライブラリ]を使用します。

2初期設定

APIテストを実行するにはユーザーが必要です。 APIに対するテストの実行を簡単にするために、アプリケーションブートストラップで、事前にテストユーザーを作成します。

@Component
public class Setup {
    @Autowired
    private UserRepository userRepository;

    @Autowired
    private PreferenceRepository preferenceRepository;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @PostConstruct
    private void createTestUser() {
        User userJohn = userRepository.findByUsername("john");
        if (userJohn == null) {
            userJohn = new User();
            userJohn.setUsername("john");
            userJohn.setPassword(passwordEncoder.encode("123"));
            userJohn.setAccessToken("token");
            userRepository.save(userJohn);
            final Preference pref = new Preference();
            pref.setTimezone(TimeZone.getDefault().getID());
            pref.setEmail("[email protected]");
            preferenceRepository.save(pref);
            userJohn.setPreference(pref);
            userRepository.save(userJohn);
        }
    }
}

Setup は単なるBeanであることに注意してください。実際のセットアップロジックには、@ @ PostConstruct__アノテーションを使用しています。

3ライブテストのサポート

実際にテストを書き始める前に、まず最初に基本的なサポート機能を設定しましょう。

認証、URLパス、そしていくつかのJSONのマーリングおよびアンマーシャル機能などが必要です。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
  classes = { TestConfig.class },
  loader = AnnotationConfigContextLoader.class)
public class AbstractLiveTest {
    public static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");

    @Autowired
    private CommonPaths commonPaths;

    protected String urlPrefix;

    protected ObjectMapper objectMapper = new ObjectMapper().setDateFormat(dateFormat);

    @Before
    public void setup() {
        urlPrefix = commonPaths.getServerRoot();
    }

    protected RequestSpecification givenAuth() {
        FormAuthConfig formConfig
          = new FormAuthConfig(urlPrefix + "/j__spring__security__check", "username", "password");
        return RestAssured.given().auth().form("john", "123", formConfig);
    }

    protected RequestSpecification withRequestBody(RequestSpecification req, Object obj)
      throws JsonProcessingException {
        return req.contentType(MediaType.APPLICATION__JSON__VALUE)
          .body(objectMapper.writeValueAsString(obj));
    }
}

実際のテストを簡単にするために、単純なヘルパーメソッドとフィールドをいくつか定義しています。

  • givenAuth() :認証を実行します

  • withRequestBody() : Object のJSON表現を次のように送信します。

HTTPリクエストの本文

そして、これが私たちの単純なビーン CommonPaths です - システムのURLにきれいな抽象化を提供します:

@Component
@PropertySource({ "classpath:web-${envTarget:local}.properties" })
public class CommonPaths {

    @Value("${http.protocol}")
    private String protocol;

    @Value("${http.port}")
    private String port;

    @Value("${http.host}")
    private String host;

    @Value("${http.address}")
    private String address;

    public String getServerRoot() {
        if (port.equals("80")) {
            return protocol + "://" + host + "/" + address;
        }
        return protocol + "://" + host + ":" + port + "/" + address;
    }
}

そしてローカルバージョンのプロパティファイル: web-local.properties :

http.protocol=http
http.port=8080
http.host=localhost
http.address=reddit-scheduler

最後に、非常に単純なテストSpringの設定:

@Configuration
@ComponentScan({ "org.baeldung.web.live" })
public class TestConfig {
    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }
}

** 4/s _cheduledPosts _ APIをテストします.

**

最初にテストするAPIは /schedulePosts APIです。

public class ScheduledPostLiveTest extends AbstractLiveTest {
    private static final String date = "2016-01-01 00:00";

    private Post createPost() throws ParseException, IOException {
        Post post = new Post();
        post.setTitle("test");
        post.setUrl("test.com");
        post.setSubreddit("test");
        post.setSubmissionDate(dateFormat.parse(date));

        Response response = withRequestBody(givenAuth(), post)
          .post(urlPrefix + "/api/scheduledPosts?date=" + date);

        return objectMapper.reader().forType(Post.class).readValue(response.asString());
    }
}

まず、新しい投稿のスケジュールをテストしましょう。

@Test
public void whenScheduleANewPost__thenCreated()
  throws ParseException, IOException {
    Post post = new Post();
    post.setTitle("test");
    post.setUrl("test.com");
    post.setSubreddit("test");
    post.setSubmissionDate(dateFormat.parse(date));

    Response response = withRequestBody(givenAuth(), post)
      .post(urlPrefix + "/api/scheduledPosts?date=" + date);

    assertEquals(201, response.statusCode());
    Post result = objectMapper.reader().forType(Post.class).readValue(response.asString());
    assertEquals(result.getUrl(), post.getUrl());
}

次に、ユーザーの 予定されているすべての投稿を取得する ことをテストしましょう。

@Test
public void whenGettingUserScheduledPosts__thenCorrect()
  throws ParseException, IOException {
    createPost();

    Response response = givenAuth().get(urlPrefix + "/api/scheduledPosts?page=0");

    assertEquals(201, response.statusCode());
    assertTrue(response.as(List.class).size() > 0);
}

次に、スケジュールされた投稿の編集** をテストしましょう。

@Test
public void whenUpdatingScheduledPost__thenUpdated()
  throws ParseException, IOException {
    Post post = createPost();

    post.setTitle("new title");
    Response response = withRequestBody(givenAuth(), post).
      put(urlPrefix + "/api/scheduledPosts/" + post.getId() + "?date=" + date);

    assertEquals(200, response.statusCode());
    response = givenAuth().get(urlPrefix + "/api/scheduledPosts/" + post.getId());
    assertTrue(response.asString().contains(post.getTitle()));
}

最後に、APIで 削除操作 をテストしましょう。

@Test
public void whenDeletingScheduledPost__thenDeleted()
  throws ParseException, IOException {
    Post post = createPost();
    Response response = givenAuth().delete(urlPrefix + "/api/scheduledPosts/" + post.getId());

    assertEquals(204, response.statusCode());
}

** 5/ sites API +をテストします.

**

次に、Sitesリソース(ユーザーが定義したサイト)を公開するAPIをテストしましょう。

public class MySitesLiveTest extends AbstractLiveTest {

    private Site createSite() throws ParseException, IOException {
        Site site = new Site("/feed/");
        site.setName("baeldung");

        Response response = withRequestBody(givenAuth(), site)
          .post(urlPrefix + "/sites");

        return objectMapper.reader().forType(Site.class).readValue(response.asString());
    }
}

ユーザーのすべてのサイトを取得する** テストをしましょう

@Test
public void whenGettingUserSites__thenCorrect()
  throws ParseException, IOException {
    createSite();
    Response response = givenAuth().get(urlPrefix + "/sites");

    assertEquals(200, response.statusCode());
    assertTrue(response.as(List.class).size() > 0);
}

また、サイトの記事を取得する:

@Test
public void whenGettingSiteArticles__thenCorrect()
  throws ParseException, IOException {
    Site site = createSite();
    Response response = givenAuth().get(urlPrefix + "/sites/articles?id=" + site.getId());

    assertEquals(200, response.statusCode());
    assertTrue(response.as(List.class).size() > 0);
}

次に、 新しいサイトを追加する ことをテストしましょう。

@Test
public void whenAddingNewSite__thenCorrect()
  throws ParseException, IOException {
    Site site = createSite();

    Response response = givenAuth().get(urlPrefix + "/sites");
    assertTrue(response.asString().contains(site.getUrl()));
}

そしてそれを 削除 します。

@Test
public void whenDeletingSite__thenDeleted() throws ParseException, IOException {
    Site site = createSite();
    Response response = givenAuth().delete(urlPrefix + "/sites/" + site.getId());

    assertEquals(204, response.statusCode());
}

6. /user/preferences API をテストします.

最後に、ユーザーの設定を公開するAPIに注目しましょう。

まず、 ユーザーの好みを取得する ことをテストしましょう。

@Test
public void whenGettingPrefernce__thenCorrect() {
    Response response = givenAuth().get(urlPrefix + "/user/preference");

    assertEquals(200, response.statusCode());
    assertTrue(response.as(Preference.class).getEmail().contains("john"));
}

そしてそれらを 編集 します。

@Test
public void whenUpdattingPrefernce__thenCorrect()
  throws JsonProcessingException {
    Preference pref = givenAuth().get(urlPrefix + "/user/preference").as(Preference.class);
    pref.setEmail("[email protected]");
    Response response = withRequestBody(givenAuth(), pref).
      put(urlPrefix + "/user/preference/" + pref.getId());

    assertEquals(200, response.statusCode());
    response = givenAuth().get(urlPrefix + "/user/preference");
    assertEquals(response.as(Preference.class).getEmail(), pref.getEmail());
}

7. 結論

このクイック記事では、REST APIの基本的なテストをいくつかまとめました。

気を引くものは何もありません - より高度なシナリオが必要です - しかし** これは完璧ではなく、進歩と公の場での繰り返しについてです。

前の投稿:Protected:JNDIデータソースを使ったSpring Persistence(HibernateとJPA)
次の投稿:Thymeleafでブール値を処理する