Đầu tiên, kiến thức của tôi ở đâu:
Unit Test là những bài kiểm tra một đoạn mã nhỏ (chủ yếu là các phương pháp đơn lẻ).
Các bài kiểm tra tích hợp là những bài kiểm tra sự tương tác giữa nhiều vùng mã (hy vọng đã có các bài kiểm tra đơn vị của riêng chúng). Đôi khi, các phần của mã đang được kiểm tra yêu cầu mã khác hoạt động theo một cách cụ thể. Đây là lúc Mocks & Stubs xuất hiện. Vì vậy, chúng tôi mô phỏng / trích xuất một phần của mã để thực hiện rất cụ thể. Điều này cho phép Kiểm tra tích hợp của chúng tôi chạy có thể dự đoán trước mà không có tác dụng phụ.
Tất cả các thử nghiệm sẽ có thể chạy độc lập mà không cần chia sẻ dữ liệu. Nếu việc chia sẻ dữ liệu là cần thiết, đây là dấu hiệu hệ thống chưa đủ tách rời.
Tiếp theo, tình huống tôi đang gặp phải:
Khi tương tác với một API bên ngoài (cụ thể là một API RESTful sẽ sửa đổi dữ liệu trực tiếp với một yêu cầu POST), tôi hiểu rằng chúng ta có thể (nên?) Mô phỏng tương tác với API đó (được nêu một cách hùng hồn hơn trong câu trả lời này ) để Kiểm tra tích hợp . Tôi cũng hiểu rằng chúng tôi có thể Unit Test từng thành phần tương tác với API đó (xây dựng yêu cầu, phân tích cú pháp kết quả, đưa ra lỗi, v.v.). Những gì tôi không nhận được là làm thế nào để thực sự đi về điều này.
Vì vậy, cuối cùng: (Các) câu hỏi của tôi.
Làm cách nào để kiểm tra sự tương tác của tôi với một API bên ngoài có tác dụng phụ?
Một ví dụ hoàn hảo là API nội dung của Google để mua sắm . Để có thể thực hiện nhiệm vụ trước mắt, nó đòi hỏi một lượng công việc chuẩn bị kha khá, sau đó thực hiện yêu cầu thực tế, sau đó phân tích giá trị trả về. Một số điều này không có bất kỳ môi trường 'hộp cát' nào .
Mã để làm điều này thường có khá nhiều lớp trừu tượng, giống như:
<?php
class Request
{
public function setUrl(..){ /* ... */ }
public function setData(..){ /* ... */ }
public function setHeaders(..){ /* ... */ }
public function execute(..){
// Do some CURL request or some-such
}
public function wasSuccessful(){
// some test to see if the CURL request was successful
}
}
class GoogleAPIRequest
{
private $request;
abstract protected function getUrl();
abstract protected function getData();
public function __construct() {
$this->request = new Request();
$this->request->setUrl($this->getUrl());
$this->request->setData($this->getData());
$this->request->setHeaders($this->getHeaders());
}
public function doRequest() {
$this->request->execute();
}
public function wasSuccessful() {
return ($this->request->wasSuccessful() && $this->parseResult());
}
private function parseResult() {
// return false when result can't be parsed
}
protected function getHeaders() {
// return some GoogleAPI specific headers
}
}
class CreateSubAccountRequest extends GoogleAPIRequest
{
private $dataObject;
public function __construct($dataObject) {
parent::__construct();
$this->dataObject = $dataObject;
}
protected function getUrl() {
return "http://...";
}
protected function getData() {
return $this->dataObject->getSomeValue();
}
}
class aTest
{
public function testTheRequest() {
$dataObject = getSomeDataObject(..);
$request = new CreateSubAccountRequest($dataObject);
$request->doRequest();
$this->assertTrue($request->wasSuccessful());
}
}
?>
Lưu ý: Đây là một ví dụ PHP5 / PHPUnit
Cho rằng đó testTheRequest
là phương thức được gọi bởi bộ thử nghiệm, ví dụ sẽ thực hiện một yêu cầu trực tiếp.
Bây giờ, yêu cầu trực tiếp này sẽ (hy vọng, với điều kiện mọi thứ diễn ra tốt đẹp) thực hiện một yêu cầu ĐĂNG có tác dụng phụ là thay đổi dữ liệu trực tiếp.
điều này có chấp nhận được không? Tôi có những lựa chọn thay thế nào? Tôi không thể thấy cách nào để mô phỏng đối tượng Yêu cầu cho bài kiểm tra. Và ngay cả khi tôi đã làm vậy, điều đó có nghĩa là thiết lập kết quả / điểm nhập cho mọi đường dẫn mã có thể mà API của Google chấp nhận (trong trường hợp này sẽ phải được tìm thấy bằng cách thử và sai), nhưng sẽ cho phép tôi sử dụng đồ đạc.
Một phần mở rộng hơn nữa là khi một số yêu cầu nhất định dựa trên một số dữ liệu nhất định đang Trực tiếp. Sử dụng lại Google Content API làm ví dụ, để thêm Nguồn cấp dữ liệu vào Tài khoản phụ, thì Tài khoản phụ phải tồn tại.
Một cách tiếp cận mà tôi có thể nghĩ đến là các bước sau;
- Trong
testCreateAccount
- Tạo một tài khoản phụ
- Khẳng định tài khoản phụ đã được tạo
- Xóa tài khoản phụ
- Có
testCreateDataFeed
phụ thuộc vàotestCreateAccount
không có bất kỳ lỗi- Trong
testCreateDataFeed
, tạo một tài khoản mới - Tạo nguồn cấp dữ liệu
- Khẳng định nguồn cấp dữ liệu đã được tạo
- Xóa nguồn cấp dữ liệu
- Xóa tài khoản phụ
- Trong
Điều này sau đó đặt ra câu hỏi xa hơn; làm cách nào để kiểm tra việc xóa tài khoản / nguồn cấp dữ liệu? testCreateDataFeed
Tôi cảm thấy bẩn - Điều gì sẽ xảy ra nếu việc tạo nguồn cấp dữ liệu không thành công? Kiểm tra không thành công, do đó tài khoản phụ không bao giờ bị xóa ... Tôi không thể kiểm tra xóa mà không tạo, vì vậy tôi viết một kiểm tra khác ( testDeleteAccount
) dựa vào testCreateAccount
trước khi tạo sau đó xóa tài khoản của chính nó (vì dữ liệu không nên được chia sẻ giữa các lần kiểm tra).
Tóm tắt
- Làm cách nào để kiểm tra việc tương tác với một API bên ngoài ảnh hưởng đến dữ liệu trực tiếp?
- Làm cách nào để tôi có thể mô phỏng / sơ khai các đối tượng trong bài kiểm tra Tích hợp khi chúng bị ẩn sau các lớp trừu tượng?
- Tôi phải làm gì khi kiểm tra không thành công và dữ liệu trực tiếp bị để ở trạng thái không nhất quán?
- Làm thế nào trong mã để tôi thực sự làm tất cả những điều này?
Có liên quan: