Chromiumでテストを書く時以下のように`IN_PROC_BROWSER_TEST_F`などのマクロを使用して宣言する。
```cpp=
IN_PROC_BROWSER_TEST_F(TooltipBrowserTest,
ShowTooltipFromWebContentWithCursor) {
NavigateToURL("/tooltip.html");
std::u16string expected_text = u"my tooltip";
...; // test content
}
```
特にテストの名前の先頭にDISABLEDとかいれるとテストが勝手にdisableされてくれる。
一体何をしてる?
## マクロ内のしごと
マクロの定義は[browser_test.h](https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:content/public/test/browser_test.h)の中にある。
1つ目の引数(上の例では`TooltipBrowserTest`)が`test_case_name`に、2つ目の引数(上の例では`ShoTooltipFromWebContentWithCursor`)が`test_name`に入る。
大きく分けて3つのことをしている。
1. テストクラスの生成
2. TestInfoを生成して登録
3. Runするためのメソッドの定義
まず[GTEST_TEST_CLASS_NAME_](https://source.chromium.org/chromium/chromium/src/+/main:third_party/googletest/src/googletest/include/gtest/internal/gtest-internal.h;l=1533;drc=b007c54f2944e193ac44fba1bc997cb65826a0b9)マクロで`test_case_name`と`test_name`からクラス名を生成する。
```cpp=
#define GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \
test_suite_name##_##test_name##_Test
```
上の例の場合は`TooltipBrowserTest_ShowTooltipFromWebContentWithCursor_Test`になる。
このクラスは`parent_class`を継承する。この場合[`TooltipBrowserTest`](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ui/views/tooltip/tooltip_browsertest.cc;l=144;drc=e6361d070be0adc585ebbff89fec76e2df4ad768)クラスがこれに相当する。
このマクロが正しく動くためにはInProcessBrowserTestを継承したクラスが親である必要があり、これらのクラスは基本テストのccファイルの中で宣言されている。
InProcessBrowserTestであれば[RunTestOnMainThread](https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:content/public/test/browser_test.h;l=69;drc=a328097ef1d47f51e76917b80110863037f4f744)がoverrideできコンパイルが通るようになっている。
生成したクラスの`test_info_`メンバにtesting::TestInfoを作って入れる。
TestInfoはgoogletestライブラリの中にある[MakeAndRegisterTestInfo](https://source.chromium.org/chromium/chromium/src/+/main:third_party/googletest/src/googletest/include/gtest/internal/gtest-internal.h;l=586;drc=b007c54f2944e193ac44fba1bc997cb65826a0b9)から生成。
この関数では生成したTestInfoをGoogle Testに登録している。
```cpp=
TestInfo* MakeAndRegisterTestInfo(
const char* test_suite_name, const char* name, const char* type_param,
const char* value_param, CodeLocation code_location,
TypeId fixture_class_id, SetUpTestSuiteFunc set_up_tc,
TearDownTestSuiteFunc tear_down_tc, TestFactoryBase* factory) {
TestInfo* const test_info =
new TestInfo(test_suite_name, name, type_param, value_param,
code_location, fixture_class_id, factory);
GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info);
return test_info;
}
```
TestInfoにはtest suite name, test nameの他にいろいろなパラメータを設定することが出来る。
IN_PROC_BROWSER_TEST_Fの場合は
`code_location`に`::testing::internal::CodeLocation(__FILE__, __LINE__)`
`set_up_tc`にparent_class::SetUpTestCase
`tear_down_tc`にparent_class::TearDownTestCaseを代入している。
SetUpTestCaseやTearDownTestCaseは[testing::Test](https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:third_party/googletest/src/googletest/include/gtest/gtest.h;l=257-258;drc=a328097ef1d47f51e76917b80110863037f4f744)の中で定義されている。なおInProcessBrowserTestやcontent::BrowserTestなど各テストクラスはすべてtesting::Testを継承しているので、ちゃんと定義されている。
クラスの定義、TestInfoの登録ができたら、定義したクラス`TooltipBrowserTest_ShowTooltipFromWebContentWithCursor_Test`に対するRunTestOnMainThread()の実装を与える。
なので、このマクロでは`void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::RunTestOnMainThread()`までとなっており、上の例のようにIN_PROCESS_BROWSER_TEST_Fマクロに続けて`{ // test content }`と書けばRunTestOnMainThread()に対する実装を与えていることになる。
ここで作ったメソッドはBrowserTestでは[BrowserTestBase::ProxyRunTestOnMainThreadLoop](https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:content/public/test/browser_test_base.cc;l=914;drc=a328097ef1d47f51e76917b80110863037f4f744)で呼ばれる。この時テストが走り終わるまで`base::ScopedDisallowBlocking`でスレッドをブロックしており、終わったらTearDownOnMainThreadが呼ばれる。
ではこの[BrowserTestBase::ProxyRunTestOnMainThreadLoop](https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:content/public/test/browser_test_base.cc;l=914;drc=a328097ef1d47f51e76917b80110863037f4f744)がどう呼ばれるかというと、まず[BrowserTestBase::SetUp](https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:content/public/test/browser_test_base.cc;l=297;drc=a328097ef1d47f51e76917b80110863037f4f744)で`ui_task`にbase::BindOnceして渡され、後で[Run](https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:content/public/test/browser_test_base.cc;l=721;drc=a328097ef1d47f51e76917b80110863037f4f744)される。この時initializeを正しく待つためにNetableTasksAllowedなRunLoopを使っている。
## Testはどうやって走るか?
[TestSuite](https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:third_party/googletest/src/googletest/include/gtest/gtest.h;l=652;drc=a328097ef1d47f51e76917b80110863037f4f744)はTestInfoからなるvectorの[`test_info_list_`](https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:third_party/googletest/src/googletest/include/gtest/gtest.h;l=835;drc=a328097ef1d47f51e76917b80110863037f4f744)を持つ。ここには上のセクションで言及した[MakeAndRegisterTestInfo](https://source.chromium.org/chromium/chromium/src/+/main:third_party/googletest/src/googletest/include/gtest/internal/gtest-internal.h;l=586;drc=b007c54f2944e193ac44fba1bc997cb65826a0b9)によって登録されている。
この中のTestInfoたちは[TestSuite::Run](https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:third_party/googletest/src/googletest/src/gtest.cc;l=2981;drc=a328097ef1d47f51e76917b80110863037f4f744)によってtriggerされる。
このRunは[TestSuite::Run](https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:base/test/test_suite.cc;l=419;drc=a328097ef1d47f51e76917b80110863037f4f744)->[RUN_ALL_TESTS()](https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:third_party/googletest/src/googletest/include/gtest/gtest.h;l=2284;drc=a328097ef1d47f51e76917b80110863037f4f744)マクロ->[UnitTest::Run](https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:third_party/googletest/src/googletest/src/gtest.cc;l=5363;drc=a328097ef1d47f51e76917b80110863037f4f744)->[UnitTestImpl::RunAllTests](https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:third_party/googletest/src/googletest/src/gtest.cc;l=5744;drc=a328097ef1d47f51e76917b80110863037f4f744)から[`test_suites_`](https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:third_party/googletest/src/googletest/src/gtest-internal-inl.h;l=859;drc=a328097ef1d47f51e76917b80110863037f4f744)に存在するすべてのTestSuiteに対し発火されている。
使用例を見てみる。
これはash_crosapi_testで使われている。
[`CrosapiTestSuite`](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ash/crosapi/test/ash_crosapi_tests_main.cc;l=20;drc=14b9b14728983afc9d06a5ab683c49ef7e56d753)はbase::TestSuiteを継承して作られているが、このRun関数を[LaunchUnitTestSerially](https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:base/test/launcher/unit_test_launcher.cc;l=294;drc=a328097ef1d47f51e76917b80110863037f4f744)の`run_test_suite`コールバックとしてわたし、実際に[RunTestSuite](https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:base/test/launcher/unit_test_launcher.cc;l=179;drc=a328097ef1d47f51e76917b80110863037f4f744)の中で走っている。
このようにテストの実行ファイルにおけるmain関数からほぼ直接TestSuite::Runを呼んで、登録されたテストすべてを走らせている。
## DISABLEDマクロ
以下のようにテストをDisableすることができる。
```cpp=
#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX)
#define MAYBE_ShowTooltipFromWebContentWithKeyboard \
DISABLED_ShowTooltipFromWebContentWithKeyboard
#else
#define MAYBE_ShowTooltipFromWebContentWithKeyboard \
ShowTooltipFromWebContentWithKeyboard
#endif
IN_PROC_BROWSER_TEST_F(TooltipBrowserTest,
MAYBE_ShowTooltipFromWebContentWithKeyboard) {
// test content
}
```
テストの名前を変えるだけでどうやってフィルターしているのか?
このDISABLEDという名前はTestInfoの中に`is_disabled`メンバとして情報が格納され、Filterに使われている。
[UnitTestImpl::FilterTests](https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:third_party/googletest/src/googletest/src/gtest.cc;l=6038;drc=a328097ef1d47f51e76917b80110863037f4f744)でTestInfo::is_disabled_が以下のように更新されている。
```cpp=
static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*";
...;
const UnitTestFilter disable_test_filter(kDisableTestFilter);;
...;
const std::string test_name(test_info->name());
const bool is_disabled =
disable_test_filter.MatchesName(test_suite_name) ||
disable_test_filter.MatchesName(test_name);
test_info->is_disabled_ = is_disabled;
```