def setUp(self): # Call superclass implementation to create the workspace super(SuiteRunnerFactoryTest, self).setUp() # Create mock instances to be returned by the constructors # of each mock class. self.mock_desc = mock.MagicMock(SuiteDescription) self.mock_renderer = mock.MagicMock(SuiteRenderer) self.mock_server = mock.MagicMock(SuitePageServer) self.mock_console_result = mock.MagicMock(ConsoleResultReporter) self.mock_xunit_result = mock.MagicMock(XUnitResultReporter) self.mock_html_coverage = mock.MagicMock(HtmlCoverageReporter) self.mock_xml_coverage = mock.MagicMock(XmlCoverageReporter) self.mock_browser = mock.MagicMock(Browser) self.mock_runner = mock.MagicMock(SuiteRunner) # Create mocks for each class that the factory will instantiate self.mock_desc_class = mock.MagicMock(return_value=self.mock_desc) self.mock_renderer_class = mock.MagicMock(return_value=self.mock_renderer) self.mock_server_class = mock.MagicMock(return_value=self.mock_server) self.mock_console_result_class = mock.MagicMock(return_value=self.mock_console_result) self.mock_xunit_result_class = mock.MagicMock(return_value=self.mock_xunit_result) self.mock_html_coverage_class = mock.MagicMock(return_value=self.mock_html_coverage) self.mock_xml_coverage_class = mock.MagicMock(return_value=self.mock_xml_coverage) self.mock_browser_class = mock.MagicMock(return_value=self.mock_browser) # Create the factory self.factory = SuiteRunnerFactory( desc_class=self.mock_desc_class, renderer_class=self.mock_renderer_class, server_class=self.mock_server_class, console_result_class=self.mock_console_result_class, xunit_result_class=self.mock_xunit_result_class, html_coverage_class=self.mock_html_coverage_class, xml_coverage_class=self.mock_xml_coverage_class, browser_class=self.mock_browser_class )
class SuiteRunnerFactoryTest(TempWorkspaceTestCase): def setUp(self): # Call superclass implementation to create the workspace super(SuiteRunnerFactoryTest, self).setUp() # Create mock instances to be returned by the constructors # of each mock class. self.mock_desc = mock.MagicMock(SuiteDescription) self.mock_renderer = mock.MagicMock(SuiteRenderer) self.mock_server = mock.MagicMock(SuitePageServer) self.mock_console_result = mock.MagicMock(ConsoleResultReporter) self.mock_xunit_result = mock.MagicMock(XUnitResultReporter) self.mock_html_coverage = mock.MagicMock(HtmlCoverageReporter) self.mock_xml_coverage = mock.MagicMock(XmlCoverageReporter) self.mock_browser = mock.MagicMock(Browser) self.mock_runner = mock.MagicMock(SuiteRunner) # Create mocks for each class that the factory will instantiate self.mock_desc_class = mock.MagicMock(return_value=self.mock_desc) self.mock_renderer_class = mock.MagicMock(return_value=self.mock_renderer) self.mock_server_class = mock.MagicMock(return_value=self.mock_server) self.mock_console_result_class = mock.MagicMock(return_value=self.mock_console_result) self.mock_xunit_result_class = mock.MagicMock(return_value=self.mock_xunit_result) self.mock_html_coverage_class = mock.MagicMock(return_value=self.mock_html_coverage) self.mock_xml_coverage_class = mock.MagicMock(return_value=self.mock_xml_coverage) self.mock_browser_class = mock.MagicMock(return_value=self.mock_browser) # Create the factory self.factory = SuiteRunnerFactory( desc_class=self.mock_desc_class, renderer_class=self.mock_renderer_class, server_class=self.mock_server_class, console_result_class=self.mock_console_result_class, xunit_result_class=self.mock_xunit_result_class, html_coverage_class=self.mock_html_coverage_class, xml_coverage_class=self.mock_xml_coverage_class, browser_class=self.mock_browser_class ) def test_configure_browsers(self): # Build a runner and configure it to test using these browsers browser_names = ['chrome', 'firefox', 'phantomjs'] _, browsers = self._build_runner(1, browser_names=browser_names, coverage_xml_path='coverage.xml', coverage_html_path='coverage.html', timeout_sec=5) # Expect that the browsers were created using the provided timeout call_args = self.mock_browser_class.call_args_list for _, kwargs in call_args: timeout_sec = kwargs.get('timeout_sec') self.assertEqual(timeout_sec, 5) # Expect that the suite runner was configured with the correct browsers expected_browsers = [self.mock_browser] * len(browser_names) self.assertEqual(browsers, expected_browsers) def test_configure_server(self): # Build the runner num_suites = 5 self._build_runner(num_suites) # Expect that the suite page server is correctly configured # Because of the way we configure the mocks, each suite description # should be identical. Check that we get the right number. suite_desc_list = [self.mock_desc for _ in range(num_suites)] self.mock_server_class.assert_called_with(suite_desc_list, self.mock_renderer, jscover_path=None) def test_configure_suite_desc(self): # Build the runner # Ignore the return value because we are checking for calls the # factory makes to our mocks. num_suites = 5 self._build_runner(num_suites) # Retrieve all the file paths passed to SuiteDescription constructors all_paths = [] all_root_dirs = [] for (args, _) in self.mock_desc_class.call_args_list: file_handle = args[0] all_paths.append(file_handle.name) all_root_dirs.append(args[1]) # Expect that all the paths we passed to the factory were used # to instantiate SuiteDescription instances for suite_path in self._suite_paths(num_suites): self.assertIn(suite_path, all_paths) # Expect that all the root dirs are the temp directory # (where we created the description file) for root_dir in all_root_dirs: self.assertEqual( os.path.realpath(root_dir), os.path.realpath(self.temp_dir) ) def test_configure_coverage(self): # Build the runner # Ignore the return value because we are checking for calls the # factory makes to our mocks. html_path = 'coverage.html' xml_path = 'coverage.xml' runner, _ = self._build_runner( 1, coverage_html_path=html_path, coverage_xml_path=xml_path ) # Expect that the coverage reporters were configured correctly self.mock_html_coverage_class.assert_called_with(html_path) self.mock_xml_coverage_class.assert_called_with(xml_path) self.assertEqual( runner.coverage_reporters(), [self.mock_xml_coverage, self.mock_html_coverage] ) def test_configure_jscover(self): # Set the environment variable to configure # JSCover (used by the server to instrument # the JavaScript sources for coverage) with mock.patch.dict('os.environ', JSCOVER_JAR='jscover.jar'): runner, _ = self._build_runner(1, coverage_xml_path='coverage.xml') # Expect that the server was configured with the JSCover JAR path _, kwargs = self.mock_server_class.call_args self.assertEqual(kwargs.get('jscover_path'), 'jscover.jar') self.assertEqual( runner.coverage_reporters(), [self.mock_xml_coverage] ) def test_configure_coverage_but_no_report(self): # Build a runner with no coverage report # But DO configure the JSCover environment variable with mock.patch.dict('os.environ', JSCOVER_JAR='jscover.jar'): runner, _ = self._build_runner( 1, coverage_xml_path=None, coverage_html_path=None ) # Expect that the server was NOT configured to use coverage _, kwargs = self.mock_server_class.call_args self.assertEqual(kwargs.get('jscover_path'), None) self.assertEqual(runner.coverage_reporters(), []) def test_configure_console_result(self): runner, _ = self._build_runner(1) # By default, only a console reporter is configured self.assertEqual( runner.result_reporters(), [self.mock_console_result] ) # The console reporter should be configured # to send results to stdout self.mock_console_result_class.assert_called_with(sys.stdout) def test_configure_xunit_result(self): runner, _ = self._build_runner(1, xunit_path='foo.txt') # Should configure the runner to generate both # console and xunit reports self.assertEqual( runner.result_reporters(), [self.mock_console_result, self.mock_xunit_result] ) # XUnit reporter should be configured with the right path args, _ = self.mock_xunit_result_class.call_args self.assertTrue(isinstance(args[0], file)) self.assertEqual(args[0].name, 'foo.txt') def test_invalid_browser_names(self): with self.assertRaises(UnknownBrowserError): self._build_runner(1, browser_names=['chrome', 'invalid']) def test_empty_browser_name_list(self): with self.assertRaises(ValueError): self._build_runner(1, browser_names=[]) @staticmethod def _suite_paths(num_suites): """ Return a list of unique suite file paths of length `num_suites`. """ return ['suite_{}.yaml'.format(num) for num in range(num_suites)] def _build_runner(self, num_suites, xunit_path=None, coverage_xml_path=None, coverage_html_path=None, browser_names=None, timeout_sec=None): """ Build a configured `SuiteRunner` instance using the `SuiteRunnerFactory`. `num_suites` is the number of suite descriptions to use. `xunit_path` is the path to the XUnit (XML) test result file. `coverage_xml_path` and `coverage_html_path` are the paths to the coverage reports to be generated. `browser_names` is a list of browser names to use in the suite descriptions. `timeout_sec` is the number of seconds to wait for a page to load before timing out Because we are using mock dependencies that always return the same values, each suite runner will be identical, and they will all use the same browser dependencies. Returns a tuple `(suite_runner, browsers)`. See `SuiteRunnerFactory.build_runner()` for details. """ # Supply default browser names if browser_names is None: browser_names = ['chrome'] # Create fake suite description files suite_path_list = self._suite_paths(num_suites) for path in suite_path_list: with open(path, 'w') as file_handle: file_handle.write('test file') # Build the suite runner instances return self.factory.build_runner( suite_path_list, browser_names, xunit_path, coverage_xml_path, coverage_html_path, timeout_sec )