add drogon test Chinese doc

Martin Chang 2021-06-28 15:05:49 +08:00
parent 1998c4f631
commit 79875eb4f7
2 changed files with 189 additions and 2 deletions

185
CHN-18-测试框架.md Normal file

@ -0,0 +1,185 @@
DrogonTest 是一个内置在 Drogon 中的最小测试框架,可实现简单的异步测试和同步测试。 它用于 Drogon 自己的单元测试和集成测试。 但也可用于测试使用 Drogon 构建的应用程序。 DrogonTest 的语法受到 [GTest](https://github.com/google/googletest) 和 [Catch2](https://github.com/catchorg/Catch2) 的启发。
您不必为应用程序使用 DrgonTest。您可以使用喜欢的任何东西。但它是一个选择。
### 基本测试
让我们从一个简单的例子开始。您有一个函数,可以计算至某数为止之自然数之和,并想测试它的正确性。
```c++
// Tell DrogonTest to generate `test::run()`. Only defined this in the main file
#define DROGON_TEST_MAIN
#include <drogon/drogon_test.h>
int sum_all(int n)
{
int result = 1;
for(int i=2;i<n;i++) result += i;
return result;
}
DROGON_TEST(Sum)
{
CHECK(sum_all(1) == 1);
CHECK(sum_all(2) == 3);
CHECK(sum_all(3) == 6);
}
int main(int argc, char** argv)
{
return drogon::test::run(argc, argv);
}
```
编译并运行...好吧,它通过了,但有一个明显的错误。 `sum_all(0)` 应该是 0。我们可以将它添加到我们的测试中
```c++
DROGON_TEST(Sum)
{
CHECK(sum_all(0) == 0);
CHECK(sum_all(1) == 1);
CHECK(sum_all(2) == 3);
CHECK(sum_all(3) == 6);
}
```
现在测试失败了:
```
In test case Sum
↳ /path/to/your/test/main.cc:47 FAILED:
CHECK(sum_all(0) == 0)
With expansion
1 == 0
```
注意到框架在表达式的两端打印了失败的测试和实际值。 让我们可以立即看到发生了什么。 解决方法很简单:
```c++
int sum_all(int n)
{
int result = 0;
for(int i=1;i<n;i++) result += i;
return result;
}
```
### 测试的类型
DrogonTest 带有各种断言和操作。 基本的 `CHECK()` 只是检查表达式的计算结果是否为真。 如果没有,它会打印到控制台。 `CHECK_THROWS()` 检查表达式是否抛出异常。诸如此类。另一方面`REQUIRE()`检查表达式是否为真。 如果没有则从函数返回。
| 失败后/表达式 | 为真 | 抛出异常 | 没有 抛出异常 | 抛出特定异常 |
|---------------------------|------------|-------------------|--------------------|----------------------|
| 不做任何事 | CHECK | CHECK_THROWS | CHECK_NOTHROW | CHECK_THROWS_AS |
| 返回 | REQUIRE | REQUIRE_THROWS | REQUIRE_NOTHROW | REQUIRE_THROWS_AS |
| 自协程返回 | CO_REQUIRE | CO_REQUIRE_THROWS | CO_REQUIRE_NOTHROW | CO_REQUIRE_THROWS_AS |
| 杀死进程 | DEMAND | DEMAND_THROWS | DEMAND_NOTHROW | DEMAND_THROWS_AS |
让我们尝试一个稍微实际的例子。 假设我们正在测试文件的内容是否符合预期。 若程序无法打开文件则没有必要进一步检查。 因此,我们可以使用 REQUIRE 来缩短和减少重复代码。
```c++
DROGON_TEST(TestContent)
{
std::ifstream in("data.txt");
REQUIRE(in.is_open());
// Instead of
// CHECK(in.is_open() == true);
// if(in.is_open() == false)
// return;
...
}
```
同样,`CO_REQUIRE` 就像 REQUIRE。 但是用于协程。 当操作修改且不可恢复的全局状态时,可以使用`DEMAND`。 唯一合乎逻辑的做法是停止测试。
### 异步测试
Drogon 是一个异步网站框架。 它仅遵循因此 DrogonTest 支持测试异步。 DrogonTest 通过`TEST_CTX`变量跟踪测试上下文。 只需按**值**捕获变量。 例如,测试远程 API 是否成功并返回 JSON
```c++
DROGON_TEST(RemoteAPITest)
{
auto client = HttpClient::newHttpClient("http://localhost:8848");
auto req = HttpReuqest::newHttpRequest();
req->setPath("/");
client->sendRequest(req, [TEST_CTX](ReqResuelt res, const HttpResponsePtr& resp) {
// There's nothing we can do if the request didn't reach the server
// or the server generated garbage.
REQUIRE(res == ReqResult::Ok);
REQUIRE(resp != nullptr);
CHECK(resp->getStatusCode == k200Ok);
CHECK(resp->contentType() == CT_APPLICATION_JSON);
});
}
```
由于测试框架支持 C++14/17 兼容性,协程必须包装在 `AsyncTask` 中或通过 `sync_wait` 调用。
```c++
DROGON_TEST(RemoteAPITestCoro)
{
auto api_test = [TEST_CTX]() {
auto client = HttpClient::newHttpClient("http://localhost:8848");
auto req = HttpReuqest::newHttpRequest();
req->setPath("/");
auto resp = co_await client->sendRequestCoro(req);
CO_REQUIRE(resp != nullptr);
CHECK(resp->getStatusCode == k200Ok);
CHECK(resp->contentType() == CT_APPLICATION_JSON);
};
sync_wait(api_test());
}
```
### 启动 Drogon 的事件循环
一些测试需要 Drogon 的事件循环运行。 例如除非特别指定否则HTTP客户端运行在Drogon的全局事件循环上。 以下样板处理了许多边缘情况,并确保事件循环在任何测试开始之前运行:
```c++
int main()
{
std::promise<void> p1;
std::future<void> f1 = p1.get_future();
// Start the main loop on another thread
std::thread thr([&]() {
// Queues the promis to be fulfilled after starting the loop
app().getLoop()->queueInLoop([]() { p1.set_value(); });
app().run();
});
// The future is only satisfied after the event loop started
f1.get();
int status = test::run(argc, argv);
// Ask the event loop to shutdown and wait
app().getLoop()->queueInLoop([]() { app().quit(); });
thr.join();
return status;
}
```
### CMake 集成
与大多数测试框架一样DrgonTest 可以将自身集成到 CMake 中。 `ParseAndAddDrogonTest` 函数将它在源文件中看到的测试添加到 CMake 的 CTest 框架中。
```cmake
include(ParseAndAddDrogonTest)
add_executable(mytest main.cpp)
target_link_libraries(mytest PRIVATE drogon)
ParseAndAddDrogonTest(mytest)
```
现在可以通过构建系统(在本例中为 Makefile运行测试。
```bash
make test
Running tests...
Test project path/to/your/test/build/
Start 1: Sum
1/1 Test #1: Sum .................................... Passed 0.00 sec
```

@ -1,5 +1,7 @@
DrogonTest is a minimal testing framework built into drogon to enable easy asynchronous testing as well as synchronous ones. It is used for Drogon's own unittests adn integration tests. But could also be used for testing applications built with Drogon. The syntax of DrogonTest is enspired by both [GTest](https://github.com/google/googletest) and [Catch2](https://github.com/catchorg/Catch2).
You don't have to use DrogonTest for your application. Use whatever you are comfortable with. But it is an option.
### Basic testing
Let's start with a simple example. You have a synchronous function that computes the sum of natural numbers up to a given value. And you want to test it for correctness.
@ -89,7 +91,7 @@ DROGON_TEST(TestContent)
}
```
Likewise, `CO_REQUIRE` is like REQUIRE. But for coroutines. And `DEMAND` can be used when an operation failed to modify an unrecoverable global state. Which the only logical thing to do is to stop testing competely.
Likewise, `CO_REQUIRE` is like REQUIRE. But for coroutines. And `DEMAND` can be used when an operation failed and it modifies an unrecoverable global state. Which the only logical thing to do is to stop testing completely.
### Asynchronous testing
@ -163,7 +165,7 @@ int main()
### CMake integration
Like most testing frmaeworks, DrogonTest can integrate itself into CMMake. The `ParseAndAddDrogonTest` function adds tests it sees in the source file to CMake's CTest framework.
Like most testing frmaeworks, DrogonTest can integrate itself into CMake. The `ParseAndAddDrogonTest` function adds tests it sees in the source file to CMake's CTest framework.
```cmake
include(ParseAndAddDrogonTest)