---
# System prepended metadata

title: Browser Test のマクロ
tags: [Chromium-General, elkurin-daily-note]

---

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;
```