From f772dee4da63faddd34fcaf8a9c97b1c67d9dfe9 Mon Sep 17 00:00:00 2001 From: Cédric Ollivier Date: Sat, 9 Nov 2019 12:28:24 +0100 Subject: Generate Html and Xunit Behave reports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I7d5f31502ba61b61a0b1c885fe8828211bc0bc0a Signed-off-by: Cédric Ollivier (cherry picked from commit 728f5c95df4d3edbe6b3f814a270cdf3b532aef9) --- requirements.txt | 1 + upper-constraints.txt | 2 + xtesting/core/behaveframework.py | 40 +++++-------- xtesting/tests/unit/core/test_behaveframework.py | 76 ++++++++++++++---------- 4 files changed, 64 insertions(+), 55 deletions(-) diff --git a/requirements.txt b/requirements.txt index 5ea71168..ea776baf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,6 +8,7 @@ enum34;python_version=='2.7' or python_version=='2.6' or python_version=='3.3' # requests!=2.20.0 # Apache-2.0 robotframework>=3.0 behave>=1.2.6 +behave-html-formatter>=0.9.4;python_version>='3.5' mock # BSD PrettyTable<0.8 # BSD six # MIT diff --git a/upper-constraints.txt b/upper-constraints.txt index b7c0086f..1867de9f 100644 --- a/upper-constraints.txt +++ b/upper-constraints.txt @@ -1,5 +1,7 @@ robotframework===3.0.2 bandit===1.1.0 +behave===1.2.6 +behave-html-formatter===0.9.4;python_version>='3.5' pylint===1.9.5;python_version=='2.7' pylint===2.3.1;python_version=='3.6' boto3===1.7.62 diff --git a/xtesting/core/behaveframework.py b/xtesting/core/behaveframework.py index d8a61ef3..2b41614c 100644 --- a/xtesting/core/behaveframework.py +++ b/xtesting/core/behaveframework.py @@ -14,7 +14,9 @@ from __future__ import division import logging import os import time + import json +import six from behave.__main__ import main as behave_main @@ -32,7 +34,6 @@ class BehaveFramework(testcase.TestCase): def __init__(self, **kwargs): super(BehaveFramework, self).__init__(**kwargs) - self.res_dir = os.path.join(self.dir_results, self.case_name) self.json_file = os.path.join(self.res_dir, 'output.json') self.total_tests = 0 self.pass_tests = 0 @@ -42,14 +43,8 @@ class BehaveFramework(testcase.TestCase): def parse_results(self): """Parse output.json and get the details in it.""" - - try: - with open(self.json_file) as stream_: - self.response = json.load(stream_) - except IOError: - self.__logger.error("Error reading the file %s", self.json_file) - - try: + with open(self.json_file) as stream_: + self.response = json.load(stream_) if self.response: self.total_tests = len(self.response) for item in self.response: @@ -59,21 +54,14 @@ class BehaveFramework(testcase.TestCase): self.fail_tests += 1 elif item['status'] == 'skipped': self.skip_tests += 1 - except KeyError: - self.__logger.error("Error in json - %s", self.response) - - try: self.result = 100 * ( self.pass_tests / self.total_tests) - except ZeroDivisionError: - self.__logger.error("No test has been run") - - self.details = {} - self.details['total_tests'] = self.total_tests - self.details['pass_tests'] = self.pass_tests - self.details['fail_tests'] = self.fail_tests - self.details['skip_tests'] = self.skip_tests - self.details['tests'] = self.response + self.details = {} + self.details['total_tests'] = self.total_tests + self.details['pass_tests'] = self.pass_tests + self.details['fail_tests'] = self.fail_tests + self.details['skip_tests'] = self.skip_tests + self.details['tests'] = self.response def run(self, **kwargs): """Run the BehaveFramework feature files @@ -103,8 +91,12 @@ class BehaveFramework(testcase.TestCase): self.__logger.exception("Cannot create %s", self.res_dir) return self.EX_RUN_ERROR config = ['--tags='+','.join(tags), - '--format=json', - '--outfile='+self.json_file] + '--junit', '--junit-directory={}'.format(self.res_dir), + '--format=json', '--outfile={}'.format(self.json_file)] + if six.PY3: + html_file = os.path.join(self.res_dir, 'output.html') + config += ['--format=behave_html_formatter:HTMLFormatter', + '--outfile={}'.format(html_file)] for feature in suites: config.append(feature) self.start_time = time.time() diff --git a/xtesting/tests/unit/core/test_behaveframework.py b/xtesting/tests/unit/core/test_behaveframework.py index f18cac03..414d96b5 100644 --- a/xtesting/tests/unit/core/test_behaveframework.py +++ b/xtesting/tests/unit/core/test_behaveframework.py @@ -10,9 +10,12 @@ """Define the classes required to fully cover behave.""" import logging +import os import unittest import mock +import six + from xtesting.core import behaveframework __author__ = "Deepak Chandella " @@ -29,28 +32,27 @@ class ParseResultTesting(unittest.TestCase): self.test = behaveframework.BehaveFramework( case_name='behave', project_name='xtesting') - def test_raises_exc_open(self): - self.test.json_file = 'dummy_file' - self.test.response = self._response - with mock.patch('six.moves.builtins.open', - mock.mock_open()) as mock_file: - mock_file.side_effect = IOError() - self.assertRaises(IOError, self.test.parse_results()) - mock_file.assert_called_once_with('dummy_file') + @mock.patch('six.moves.builtins.open', side_effect=OSError) + def test_raises_exc_open(self, *args): # pylint: disable=unused-argument + with self.assertRaises(OSError): + self.test.parse_results() - def test_raises_exc_key(self): - with mock.patch('six.moves.builtins.open', mock.mock_open()), \ - mock.patch('json.load', return_value=[{'foo': 'bar'}]): - self.assertRaises(KeyError, self.test.parse_results()) + @mock.patch('json.load', return_value=[{'foo': 'bar'}]) + @mock.patch('six.moves.builtins.open', mock.mock_open()) + def test_raises_exc_key(self, *args): # pylint: disable=unused-argument + with self.assertRaises(KeyError): + self.test.parse_results() - def test_raises_exe_zerodivision(self): - with mock.patch('six.moves.builtins.open', mock.mock_open()), \ - mock.patch('json.load', mock.Mock(return_value=[])): - self.assertRaises(ZeroDivisionError, self.test.parse_results()) + @mock.patch('json.load', return_value=[]) + @mock.patch('six.moves.builtins.open', mock.mock_open()) + def test_raises_exe_zerodivision(self, *args): + # pylint: disable=unused-argument + with self.assertRaises(ZeroDivisionError): + self.test.parse_results() def _test_result(self, response, result): with mock.patch('six.moves.builtins.open', mock.mock_open()), \ - mock.patch('json.load', mock.Mock(return_value=response)): + mock.patch('json.load', return_value=response): self.test.parse_results() self.assertEqual(self.test.result, result) @@ -66,11 +68,10 @@ class ParseResultTesting(unittest.TestCase): data = [{'status': 'passed'}, {'status': 'passed'}] self._test_result(data, 100) - def test_count(self): + @mock.patch('six.moves.builtins.open', mock.mock_open()) + def test_count(self, *args): # pylint: disable=unused-argument self._response.extend([{'status': 'failed'}, {'status': 'skipped'}]) - with mock.patch('six.moves.builtins.open', mock.mock_open()), \ - mock.patch('json.load', mock.Mock( - return_value=self._response)): + with mock.patch('json.load', mock.Mock(return_value=self._response)): self.test.parse_results() self.assertEqual(self.test.details['pass_tests'], 1) self.assertEqual(self.test.details['fail_tests'], 1) @@ -116,11 +117,17 @@ class RunTesting(unittest.TestCase): self.assertEqual( self.test.run(suites=self.suites, tags=self.tags), self.test.EX_OK) - args[0].assert_called_once_with( - ['--tags=', - '--format=json', - '--outfile={}'.format(self.test.json_file), - 'foo']) + html_file = os.path.join(self.test.res_dir, 'output.html') + args_list = [ + '--tags=', '--junit', + '--junit-directory={}'.format(self.test.res_dir), + '--format=json', '--outfile={}'.format(self.test.json_file)] + if six.PY3: + args_list += [ + '--format=behave_html_formatter:HTMLFormatter', + '--outfile={}'.format(html_file)] + args_list.append('foo') + args[0].assert_called_once_with(args_list) mock_method.assert_called_once_with() @mock.patch('os.makedirs') @@ -144,11 +151,17 @@ class RunTesting(unittest.TestCase): self.test.run( suites=self.suites, tags=self.tags), status) - args[0].assert_called_once_with( - ['--tags=', - '--format=json', - '--outfile={}'.format(self.test.json_file), - 'foo']) + html_file = os.path.join(self.test.res_dir, 'output.html') + args_list = [ + '--tags=', '--junit', + '--junit-directory={}'.format(self.test.res_dir), + '--format=json', '--outfile={}'.format(self.test.json_file)] + if six.PY3: + args_list += [ + '--format=behave_html_formatter:HTMLFormatter', + '--outfile={}'.format(html_file)] + args_list.append('foo') + args[0].assert_called_once_with(args_list) args[1].assert_called_once_with(self.test.res_dir) def test_parse_results_exc(self): @@ -157,6 +170,7 @@ class RunTesting(unittest.TestCase): self._test_parse_results(self.test.EX_RUN_ERROR) mock_method.assert_called_once_with() + if __name__ == "__main__": logging.disable(logging.CRITICAL) unittest.main(verbosity=2) -- cgit 1.2.3-korg