Commit f9b096d8 authored by Rohit Rao's avatar Rohit Rao Committed by Commit Bot

Reland "[ios] Adds the ability to run unittests using XCTest."

Original change's description:
> Revert "[ios] Adds the ability to run unittests using XCTest."
> 
> This reverts commit b6c231b5.
> 
> Reason for revert: Suspected for causing compiling errors on mac.
> 
> Original change's description:
> > [ios] Adds the ability to run unittests using XCTest.
> > 
> > This new functionality is hidden behind both a GN arg
> > (enable_run_ios_unittests_with_xctest) and a commandline switch
> > (--enable-run-unittests-with-xctest), in order to default it to off
> > until the bots are updated to properly run XCTest-based unittests.
> > 
> > The iOS test runner is updated to run in one of two modes.  When
> > --enable-run-unittests-with-xctest is false (the default), behavior is
> > unchanged; TestSuite::Run() calls UIApplicationMain(), then the
> > UIApplicationDelegate calls TestSuite::Run() again, which actually runs
> > the tests when invoked the second time.  When the switch is set to true,
> > the second invocation of TestSuite::Run() is made by our XCTestCase
> > subclass rather than by the application delegate.
> > 
> > Xcode provides the ability to run XCTests and XCUITests from the
> > commandline, but does not provide any other way to install and run an
> > app outside of this test-based workflow.  (We had an alternative that
> > used third party libraries, but they no longer work on iOS 13.)  This
> > makes it difficult to install and run GoogleTest-based tests on iOS
> > devices, since they run as a single self-contained application, but it
> > would not be practical to drop GoogleTest support on iOS.  Instead, we
> > are exploring invoking these tests via XCTest, which would allow us to
> > use Xcode's tooling but still run the same GoogleTest-based tests as on
> > other platforms.
> > 
> > BUG=635509
> > 
> > Change-Id: I26c67d9c7e16a744f43a20f2d8c5839ca8b3c31a
> > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1787593
> > Reviewed-by: Dirk Pranke <dpranke@chromium.org>
> > Reviewed-by: Mark Mentovai <mark@chromium.org>
> > Reviewed-by: Justin Cohen <justincohen@chromium.org>
> > Commit-Queue: Rohit Rao <rohitrao@chromium.org>
> > Cr-Commit-Position: refs/heads/master@{#694749}
> 
> TBR=rohitrao@chromium.org,dpranke@chromium.org,justincohen@chromium.org,mark@chromium.org
> 
> Change-Id: Ic67605ab0292551500a163e993c6d93fec3048c0
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: 635509,1002144
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1791798
> Reviewed-by: Tarun Bansal <tbansal@chromium.org>
> Commit-Queue: Tarun Bansal <tbansal@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#694814}

TBR=rohitrao@chromium.org,dpranke@chromium.org,justincohen@chromium.org,tbansal@chromium.org,mark@chromium.org

Change-Id: I94e59823c379e1afb4e9e965bfe602d06400e8b5
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: 635509, 1002144
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1790069Reviewed-by: default avatarRohit Rao <rohitrao@chromium.org>
Reviewed-by: default avatarMark Mentovai <mark@chromium.org>
Commit-Queue: Rohit Rao <rohitrao@chromium.org>
Cr-Commit-Position: refs/heads/master@{#694950}
parent ec992a43
......@@ -228,6 +228,7 @@ static_library("test_support") {
set_sources_assignment_filter([])
sources += [ "test_file_util_mac.cc" ]
set_sources_assignment_filter(sources_assignment_filter)
deps += [ ":google_test_runner_shared_headers" ]
}
if (is_mac) {
......@@ -513,6 +514,29 @@ if (is_android) {
}
}
if (is_ios) {
source_set("google_test_runner_shared_headers") {
sources = [
"ios/google_test_runner_delegate.h",
]
}
source_set("google_test_runner") {
sources = [
"ios/google_test_runner.mm",
]
deps = [
":google_test_runner_shared_headers",
"//base",
]
libs = [ "UIKit.framework" ]
configs += [
"//build/config/compiler:enable_arc",
"//build/config/ios:xctest_config",
]
}
}
# Trivial executable which outputs space-delimited argv to stdout,
# used for testing.
executable("test_child_process") {
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import <UIKit/UIKit.h>
#import <XCTest/XCTest.h>
#include "base/logging.h"
#import "base/test/ios/google_test_runner_delegate.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
@interface GoogleTestRunner : XCTestCase
@end
@implementation GoogleTestRunner
- (void)testRunGoogleTests {
id appDelegate = UIApplication.sharedApplication.delegate;
DCHECK([appDelegate conformsToProtocol:@protocol(GoogleTestRunnerDelegate)]);
id<GoogleTestRunnerDelegate> runnerDelegate =
static_cast<id<GoogleTestRunnerDelegate>>(appDelegate);
DCHECK(runnerDelegate.supportsRunningGoogleTests);
XCTAssertTrue([runnerDelegate runGoogleTests] == 0);
}
@end
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_TEST_IOS_GOOGLE_TEST_RUNNER_DELEGATE_H_
#define BASE_TEST_IOS_GOOGLE_TEST_RUNNER_DELEGATE_H_
@protocol GoogleTestRunnerDelegate
// Returns YES if this delegate supports running GoogleTests via a call to
// |runGoogleTests|.
@property(nonatomic, readonly, assign) BOOL supportsRunningGoogleTests;
// Runs GoogleTests and returns the final exit code.
- (int)runGoogleTests;
@end
#endif // BASE_TEST_IOS_GOOGLE_TEST_RUNNER_DELEGATE_H_
......@@ -19,6 +19,9 @@ void InitIOSRunHook(TestSuite* suite, int argc, char* argv[]);
// InitIOSRunHook.
void RunTestsFromIOSApp();
// Returns true if unittests should be run by the XCTest runnner.
bool ShouldRunIOSUnittestsWithXCTest();
} // namespace base
#endif // BASE_TEST_TEST_SUPPORT_IOS_H_
......@@ -2,14 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "base/test/test_support_ios.h"
#import <UIKit/UIKit.h>
#include "base/command_line.h"
#include "base/debug/debugger.h"
#include "base/logging.h"
#include "base/mac/scoped_nsobject.h"
#include "base/message_loop/message_pump.h"
#include "base/message_loop/message_pump_default.h"
#import "base/test/ios/google_test_runner_delegate.h"
#include "base/test/test_suite.h"
#include "base/test/test_switches.h"
#include "testing/coverage_util_ios.h"
// Springboard will kill any iOS app that fails to check in after launch within
......@@ -45,7 +50,7 @@ static char** g_argv;
@end
#endif // TARGET_IPHONE_SIMULATOR
@interface ChromeUnitTestDelegate : NSObject {
@interface ChromeUnitTestDelegate : NSObject <GoogleTestRunnerDelegate> {
base::scoped_nsobject<UIWindow> _window;
}
- (void)runTests;
......@@ -86,9 +91,12 @@ static char** g_argv;
[self redirectOutput];
// Queue up the test run.
[self performSelector:@selector(runTests)
withObject:nil
afterDelay:0.1];
if (!base::ShouldRunIOSUnittestsWithXCTest()) {
// When running in XCTest mode, XCTest will invoke |runGoogleTest| directly.
// Otherwise, schedule a call to |runTests|.
[self performSelector:@selector(runTests) withObject:nil afterDelay:0.1];
}
return YES;
}
......@@ -150,7 +158,11 @@ static char** g_argv;
}
}
- (void)runTests {
- (BOOL)supportsRunningGoogleTests {
return base::ShouldRunIOSUnittestsWithXCTest();
}
- (int)runGoogleTests {
coverage_util::ConfigureCoverageReportPath();
int exitStatus = g_test_suite->Run();
......@@ -158,6 +170,14 @@ static char** g_argv;
if ([self shouldRedirectOutputToFile])
[self writeOutputToNSLog];
return exitStatus;
}
- (void)runTests {
DCHECK(!base::ShouldRunIOSUnittestsWithXCTest());
int exitStatus = [self runGoogleTests];
// If a test app is too fast, it will exit before Instruments has has a
// a chance to initialize and no test results will be seen.
// TODO(crbug.com/137010): Figure out how much time is actually needed, and
......@@ -216,4 +236,9 @@ void RunTestsFromIOSApp() {
}
}
bool ShouldRunIOSUnittestsWithXCTest() {
return base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableRunIOSUnittestsWithXCTest);
}
} // namespace base
......@@ -84,3 +84,9 @@ const char switches::kTestLauncherTrace[] = "test-launcher-trace";
const char switches::kTestTinyTimeout[] = "test-tiny-timeout";
const char switches::kUiTestActionTimeout[] = "ui-test-action-timeout";
const char switches::kUiTestActionMaxTimeout[] = "ui-test-action-max-timeout";
#if defined(OS_IOS)
// If enabled, runs unittests using the XCTest test runner.
const char switches::kEnableRunIOSUnittestsWithXCTest[] =
"enable-run-ios-unittests-with-xctest";
#endif
......@@ -5,6 +5,8 @@
#ifndef BASE_TEST_TEST_SWITCHES_H_
#define BASE_TEST_TEST_SWITCHES_H_
#include "build/build_config.h"
namespace switches {
// All switches in alphabetical order. The switches should be documented
......@@ -32,6 +34,10 @@ extern const char kTestTinyTimeout[];
extern const char kUiTestActionTimeout[];
extern const char kUiTestActionMaxTimeout[];
#if defined(OS_IOS)
extern const char kEnableRunIOSUnittestsWithXCTest[];
#endif
} // namespace switches
#endif // BASE_TEST_TEST_SWITCHES_H_
......@@ -1808,13 +1808,20 @@ template("ios_xctest_test") {
_host_target = _target_name
_host_output = _output_name
_xctest_shell_source_target = _xctest_target + "shell_source"
source_set(_xctest_shell_source_target) {
sources = [
"//build/config/ios/xctest_shell.mm",
]
# Allow invokers to specify their own target for the xctest module, but
# fall back to a default (empty) module otherwise.
if (defined(invoker.xctest_module_target)) {
_xctest_module_target = invoker.xctest_module_target
} else {
_xctest_module_target_name = _xctest_target + "shell_source"
_xctest_module_target = ":$_xctest_module_target_name"
source_set(_xctest_module_target_name) {
sources = [
"//build/config/ios/xctest_shell.mm",
]
configs += [ "//build/config/ios:xctest_config" ]
configs += [ "//build/config/ios:xctest_config" ]
}
}
ios_xctest_bundle(_xctest_target) {
......@@ -1824,7 +1831,7 @@ template("ios_xctest_test") {
xcode_test_application_name = _host_output
deps = [
":$_xctest_shell_source_target",
_xctest_module_target,
]
}
......
......@@ -293,6 +293,14 @@ template("test") {
import("//build/config/ios/ios_sdk.gni")
import("//build/config/ios/rules.gni")
declare_args() {
# Keep the unittest-as-xctest functionality defaulted to off until the
# bots are updated to handle it properly.
# TODO(crbug.com/1001667): Remove this arg once the iOS test runner
# supports running unittests with xctest.
enable_run_ios_unittests_with_xctest = false
}
_test_target = target_name
_resources_bundle_data = target_name + "_resources_bundle_data"
......@@ -306,9 +314,19 @@ template("test") {
]
}
ios_app_bundle(_test_target) {
if (enable_run_ios_unittests_with_xctest) {
ios_test_target_type = "ios_xctest_test"
} else {
ios_test_target_type = "ios_app_bundle"
}
target(ios_test_target_type, _test_target) {
testonly = true
if (enable_run_ios_unittests_with_xctest) {
xctest_module_target = "//base/test:google_test_runner"
}
# See above call.
set_sources_assignment_filter([])
forward_variables_from(invoker, "*", [ "testonly" ])
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment