1
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
3
# Autopilot Functional Test Tool
4
# Copyright (C) 2013 Canonical
6
# This program is free software: you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation, either version 3 of the License, or
9
# (at your option) any later version.
11
# This program is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
# GNU General Public License for more details.
16
# You should have received a copy of the GNU General Public License
17
# along with this program. If not, see <http://www.gnu.org/licenses/>.
24
from testtools import TestCase, PlaceHolder
25
from testtools.content import text_content
26
from testtools.matchers import Contains, raises, NotEquals
27
from testscenarios import WithScenarios
30
from autopilot import testresult
31
from autopilot import run
34
class LoggedTestResultDecoratorTests(TestCase):
36
def construct_simple_content_object(self):
37
return text_content(self.getUniqueString)
39
def test_can_construct(self):
40
testresult.LoggedTestResultDecorator(Mock())
42
def test_addSuccess_calls_decorated_test(self):
44
result = testresult.LoggedTestResultDecorator(wrapped)
45
fake_test = PlaceHolder('fake_test')
46
fake_details = self.construct_simple_content_object()
48
result.addSuccess(fake_test, fake_details)
50
wrapped.addSuccess.assert_called_once_with(
55
def test_addError_calls_decorated_test(self):
57
result = testresult.LoggedTestResultDecorator(wrapped)
58
fake_test = PlaceHolder('fake_test')
60
fake_details = self.construct_simple_content_object()
62
result.addError(fake_test, fake_error, fake_details)
64
wrapped.addError.assert_called_once_with(
70
def test_addFailure_calls_decorated_test(self):
72
result = testresult.LoggedTestResultDecorator(wrapped)
73
fake_test = PlaceHolder('fake_test')
75
fake_details = self.construct_simple_content_object()
77
result.addFailure(fake_test, fake_error, fake_details)
79
wrapped.addFailure.assert_called_once_with(
86
class OutputFormatFactoryTests(TestCase):
88
def test_has_text_format(self):
89
self.assertTrue('text' in testresult.get_output_formats())
91
def test_has_xml_format(self):
92
self.assertTrue('xml' in testresult.get_output_formats())
94
def test_has_subunit_format(self):
95
self.assertTrue('subunit' in testresult.get_output_formats())
97
def test_default_format_is_available(self):
99
testresult.get_output_formats(),
100
Contains(testresult.get_default_format())
104
class TestResultOutputStreamTests(WithScenarios, TestCase):
107
(f, dict(format=f)) for f in testresult.get_output_formats().keys()
110
def get_supported_options(self, **kwargs):
111
"""Get a dictionary of all supported keyword arguments for the current
114
Pass in keyword arguments to override default options.
116
output_path = tempfile.mktemp()
117
self.addCleanup(remove_if_exists, output_path)
119
'stream': run.get_output_stream(self.format, output_path),
122
options.update(kwargs)
125
def run_test_with_result(self, test_suite, **kwargs):
126
"""Run the given test with the current result object.
128
Returns the test result and output file path.
129
Use keyword arguments to alter result object options.
132
ResultClass = testresult.get_output_formats()[self.format]
133
result_options = self.get_supported_options(**kwargs)
134
output_path = result_options['stream'].name
135
result = ResultClass(**result_options)
136
result.startTestRun()
137
test_result = test_suite.run(result)
139
result_options['stream'].flush()
140
return test_result, output_path
142
def test_factory_function_is_a_callable(self):
144
callable(testresult.get_output_formats()[self.format])
147
def test_factory_callable_raises_on_unknown_kwargs(self):
148
factory_fn = testresult.get_output_formats()[self.format]
149
options = self.get_supported_options()
150
options['unknown_kwarg'] = True
153
lambda: factory_fn(**options),
157
def test_creates_non_empty_file_on_passing_test(self):
158
class PassingTests(TestCase):
160
def test_passes(self):
163
test_result, output_path = self.run_test_with_result(
164
PassingTests('test_passes')
166
self.assertTrue(test_result.wasSuccessful())
167
self.assertThat(open(output_path, 'rb').read(), NotEquals(b''))
169
def test_creates_non_empty_file_on_failing_test(self):
170
class FailingTests(TestCase):
172
def test_fails(self):
173
self.fail("Failing Test: ")
175
test_result, output_path = self.run_test_with_result(
176
FailingTests('test_fails')
178
self.assertFalse(test_result.wasSuccessful())
179
self.assertThat(open(output_path, 'rb').read(), NotEquals(b''))
181
def test_creates_non_empty_file_on_erroring_test(self):
182
class ErroringTests(TestCase):
184
def test_errors(self):
185
raise RuntimeError("Uncaught Exception!")
187
test_result, output_path = self.run_test_with_result(
188
ErroringTests('test_errors')
190
self.assertFalse(test_result.wasSuccessful())
191
self.assertThat(open(output_path, 'rb').read(), NotEquals(b''))
193
def test_creates_non_empty_log_file_when_failing_with_unicode(self):
194
class FailingTests(TestCase):
196
def test_fails_unicode(self):
198
u'\xa1pl\u0279oM \u01ddpo\u0254\u0131u\u2229 oll\u01ddH'
200
test_result, output_path = self.run_test_with_result(
201
FailingTests('test_fails_unicode')
203
# We need to specify 'errors="ignore"' because subunit write non-valid
205
log_contents = codecs.open(
211
self.assertFalse(test_result.wasSuccessful())
214
Contains(u'\xa1pl\u0279oM \u01ddpo\u0254\u0131u\u2229 oll\u01ddH')
217
def test_result_object_supports_many_tests(self):
218
class ManyFailingTests(TestCase):
220
def test_fail1(self):
221
self.fail("Failing test")
223
def test_fail2(self):
224
self.fail("Failing test")
225
suite = unittest.TestSuite(
227
ManyFailingTests('test_fail1'),
228
ManyFailingTests('test_fail2'),
231
test_result, output_path = self.run_test_with_result(suite)
232
self.assertFalse(test_result.wasSuccessful())
233
self.assertEqual(2, test_result.testsRun)
235
def test_result_object_supports_failfast(self):
236
class ManyFailingTests(TestCase):
238
def test_fail1(self):
239
self.fail("Failing test")
241
def test_fail2(self):
242
self.fail("Failing test")
243
suite = unittest.TestSuite(
245
ManyFailingTests('test_fail1'),
246
ManyFailingTests('test_fail2'),
249
test_result, output_path = self.run_test_with_result(
253
self.assertFalse(test_result.wasSuccessful())
254
self.assertEqual(1, test_result.testsRun)
257
def remove_if_exists(path):
258
if os.path.exists(path):