Reddit應用API測試

REST,Spring
Remote
0
06:11 PM · Dec 01 ,2025

1. 概述

我們已經一段時間了在為我們的簡單Reddit應用構建REST API——現在是時候認真起來並開始測試它

現在我們終於切換到更簡單的認證機制,也更容易進行測試。我們將使用強大的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 請求的主體發送

以下是我們的簡單 Bean – 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. 測試 /scheduledPosts API

我們要測試的第一個 API 是 /scheduledPosts 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 response2 = givenAuth().get(urlPrefix + "/api/scheduledPosts/" + post.getId());
    assertTrue(response2.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 – 用户定義的 sites:

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());
    }
}

讓我們測試檢索用户的所有 sites:

@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);
}

並且檢索 site 的文章:

@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);
}

接下來,讓我們測試添加一個新的 Site:

@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. 測試 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 response2 = givenAuth().get(urlPrefix + "/user/preference");
    assertEquals(response2.as(Preference.class).getEmail(), pref.getEmail());
}

7. 結論

在本文中,我們對我們的 REST API 進行了基本的測試。

沒有什麼花哨的 – 需要更高級的場景 – 但 這不關乎完美,而是關於進步和在公眾面前迭代

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.