Commit 99c18b0c by Gabriel Falcão

Merge pull request #311 from medwards/print_failed_steps

Print step that failed in verbosity=2
parents beaddd31 7a7b86c0
......@@ -144,7 +144,7 @@ class StepDefinition(object):
self.step.passed = True
except Exception, e:
self.step.failed = True
self.step.why = ReasonToFail(e)
self.step.why = ReasonToFail(self.step, e)
raise
return ret
......
......@@ -35,7 +35,8 @@ class ReasonToFail(object):
AssertionError raised within a step definition. With these data
lettuce show detailed traceback to user in a nice representation.
"""
def __init__(self, exc):
def __init__(self, step, exc):
self.step = step
self.exception = exc
if isinstance(exc.message, unicode):
self.cause = unicode(exc)
......
......@@ -16,70 +16,28 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import sys
from lettuce import core
from lettuce.terrain import after
from lettuce.terrain import before
from lettuce.plugins.reporter import Reporter
failed_scenarios = []
scenarios_and_its_fails = {}
class DotReporter(Reporter):
def print_scenario_ran(self, scenario):
if scenario.passed:
self.wrt(".")
elif scenario.failed:
reason = self.scenarios_and_its_fails[scenario]
if isinstance(reason.exception, AssertionError):
self.wrt("F")
else:
self.wrt("E")
reporter = DotReporter()
def wrt(what):
if isinstance(what, unicode):
what = what.encode('utf-8')
sys.stdout.write(what)
@after.each_step
def print_scenario_ran(step):
if not step.failed:
wrt(".")
elif step.failed:
if step.scenario not in failed_scenarios:
scenarios_and_its_fails[step.scenario] = step.why
failed_scenarios.append(step.scenario)
if isinstance(step.why.exception, AssertionError):
wrt("F")
else:
wrt("E")
@after.all
def print_end(total):
if total.scenarios_passed < total.scenarios_ran:
wrt("\n")
wrt("\n")
for scenario in failed_scenarios:
reason = scenarios_and_its_fails[scenario]
wrt(reason.traceback)
wrt("\n")
word = total.features_ran > 1 and "features" or "feature"
wrt("%d %s (%d passed)\n" % (
total.features_ran,
word,
total.features_passed))
word = total.scenarios_ran > 1 and "scenarios" or "scenario"
wrt("%d %s (%d passed)\n" % (
total.scenarios_ran,
word,
total.scenarios_passed))
steps_details = []
for kind in "failed", "skipped", "undefined":
attr = 'steps_%s' % kind
stotal = getattr(total, attr)
if stotal:
steps_details.append("%d %s" % (stotal, kind))
steps_details.append("%d passed" % total.steps_passed)
word = total.steps > 1 and "steps" or "step"
wrt("%d %s (%s)\n" % (
total.steps,
word,
", ".join(steps_details)))
before.each_scenario(reporter.print_scenario_running)
after.each_scenario(reporter.print_scenario_ran)
after.each_step(reporter.store_failed_step)
after.all(reporter.print_end)
def print_no_features_found(where):
......@@ -87,5 +45,5 @@ def print_no_features_found(where):
if not where.startswith(os.sep):
where = '.%s%s' % (os.sep, where)
wrt('Oops!\n')
wrt('could not find features at %s\n' % where)
reporter.wrt('Oops!\n')
reporter.wrt('could not find features at %s\n' % where)
import sys
class Reporter(object):
def __init__(self):
self.failed_scenarios = []
self.scenarios_and_its_fails = {}
def wrt(self, what):
if isinstance(what, unicode):
what = what.encode('utf-8')
sys.stdout.write(what)
def store_failed_step(self, step):
if step.failed and step.scenario not in self.failed_scenarios:
self.scenarios_and_its_fails[step.scenario] = step.why
self.failed_scenarios.append(step.scenario)
def print_scenario_running(self, scenario):
pass
def print_scenario_ran(self, scenario):
pass
def print_end(self, total):
if total.scenarios_passed < total.scenarios_ran:
self.wrt("\n")
self.wrt("\n")
for scenario in self.failed_scenarios:
reason = self.scenarios_and_its_fails[scenario]
self.wrt(str(reason.step))
self.wrt("\n")
self.wrt(reason.traceback)
self.wrt("\n")
word = total.features_ran > 1 and "features" or "feature"
self.wrt("%d %s (%d passed)\n" % (
total.features_ran,
word,
total.features_passed))
word = total.scenarios_ran > 1 and "scenarios" or "scenario"
self.wrt("%d %s (%d passed)\n" % (
total.scenarios_ran,
word,
total.scenarios_passed))
steps_details = []
for kind in "failed", "skipped", "undefined":
attr = 'steps_%s' % kind
stotal = getattr(total, attr)
if stotal:
steps_details.append("%d %s" % (stotal, kind))
steps_details.append("%d passed" % total.steps_passed)
word = total.steps > 1 and "steps" or "step"
self.wrt("%d %s (%s)\n" % (
total.steps,
word,
", ".join(steps_details)))
......@@ -16,76 +16,32 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import sys
from lettuce import core
from lettuce.terrain import after
from lettuce.terrain import before
from lettuce.plugins.reporter import Reporter
failed_scenarios = []
scenarios_and_its_fails = {}
class NameReporter(Reporter):
def print_scenario_running(self, scenario):
self.wrt('%s ... ' % scenario.name)
def print_scenario_ran(self, scenario):
if scenario.passed:
self.wrt("OK")
elif scenario.failed:
reason = self.scenarios_and_its_fails[scenario]
if isinstance(reason.exception, AssertionError):
self.wrt("FAILED")
else:
self.wrt("ERROR")
self.wrt("\n")
def wrt(what):
if isinstance(what, unicode):
what = what.encode('utf-8')
sys.stdout.write(what)
reporter = NameReporter()
@before.each_scenario
def print_scenario_running(scenario):
wrt('%s ... ' % scenario.name)
@after.each_scenario
def print_scenario_ran(scenario):
if scenario.passed:
print "OK"
elif scenario.failed:
reason = scenarios_and_its_fails[scenario]
if isinstance(reason.exception, AssertionError):
print "FAILED"
else:
print "ERROR"
@after.each_step
def save_step_failed(step):
if step.failed and step.scenario not in failed_scenarios:
scenarios_and_its_fails[step.scenario] = step.why
failed_scenarios.append(step.scenario)
@after.all
def print_end(total):
if total.scenarios_passed < total.scenarios_ran:
print # just a line to separate things here
for scenario in failed_scenarios:
reason = scenarios_and_its_fails[scenario]
wrt(reason.traceback)
wrt("\n")
word = total.features_ran > 1 and "features" or "feature"
wrt("%d %s (%d passed)\n" % (
total.features_ran,
word,
total.features_passed))
word = total.scenarios_ran > 1 and "scenarios" or "scenario"
wrt("%d %s (%d passed)\n" % (
total.scenarios_ran,
word,
total.scenarios_passed))
steps_details = []
for kind in "failed", "skipped", "undefined":
attr = 'steps_%s' % kind
stotal = getattr(total, attr)
if stotal:
steps_details.append("%d %s" % (stotal, kind))
steps_details.append("%d passed" % total.steps_passed)
word = total.steps > 1 and "steps" or "step"
wrt("%d %s (%s)\n" % (total.steps, word, ", ".join(steps_details)))
before.each_scenario(reporter.print_scenario_running)
after.each_scenario(reporter.print_scenario_ran)
after.each_step(reporter.store_failed_step)
after.all(reporter.print_end)
def print_no_features_found(where):
......@@ -93,5 +49,5 @@ def print_no_features_found(where):
if not where.startswith(os.sep):
where = '.%s%s' % (os.sep, where)
wrt('Oops!\n')
wrt('could not find features at %s\n' % where)
reporter.wrt('Oops!\n')
reporter.wrt('could not find features at %s\n' % where)
......@@ -908,6 +908,8 @@ def test_output_level_2_fail():
assert_stdout_lines_with_traceback(
"See it fail ... FAILED\n"
"\n"
"\n"
"<Step: \"And this one fails\">\n"
"Traceback (most recent call last):\n"
' File "%(lettuce_core_file)s", line %(call_line)d, in __call__\n'
" ret = self.function(self.step, *args, **kw)\n"
......@@ -936,6 +938,8 @@ def test_output_level_2_error():
"It should pass ... OK\n"
"It should raise an exception different of AssertionError ... ERROR\n"
"\n"
"\n"
"<Step: \"Given my step that blows a exception\">\n"
"Traceback (most recent call last):\n"
' File "%(lettuce_core_file)s", line %(call_line)d, in __call__\n'
" ret = self.function(self.step, *args, **kw)\n"
......@@ -977,8 +981,9 @@ def test_output_level_1_fail():
runner.run()
assert_stdout_lines_with_traceback(
".F...\n"
"F\n"
"\n"
"<Step: \"And this one fails\">\n"
"Traceback (most recent call last):\n"
' File "%(lettuce_core_file)s", line %(call_line)d, in __call__\n'
" ret = self.function(self.step, *args, **kw)\n"
......@@ -1006,6 +1011,7 @@ def test_output_level_1_error():
assert_stdout_lines_with_traceback(
".E\n"
"\n"
"<Step: \"Given my step that blows a exception\">\n"
"Traceback (most recent call last):\n"
' File "%(lettuce_core_file)s", line %(call_line)d, in __call__\n'
" ret = self.function(self.step, *args, **kw)\n"
......@@ -1060,7 +1066,7 @@ def test_blank_step_hash_value():
runner.run()
assert_stdout_lines(
"...."
"."
"\n"
"1 feature (1 passed)\n"
"1 scenario (1 passed)\n"
......@@ -1098,7 +1104,7 @@ def test_run_only_fast_tests():
runner.run()
assert_stdout_lines(
".."
"."
"\n"
"1 feature (1 passed)\n"
"1 scenario (1 passed)\n"
......@@ -1142,7 +1148,7 @@ def test_background_with_header():
runner.run()
assert_stdout_lines(
"........."
".."
"\n"
"1 feature (1 passed)\n"
"2 scenarios (2 passed)\n"
......@@ -1189,7 +1195,7 @@ def test_background_without_header():
runner.run()
assert_stdout_lines(
"........."
".."
"\n"
"1 feature (1 passed)\n"
"2 scenarios (2 passed)\n"
......@@ -1229,10 +1235,10 @@ def test_output_background_with_success_colorless():
' I want to automate its test # tests/functional/bg_features/simple/simple.feature:4\n'
'\n'
' Background:\n'
' Given the variable "X" holds 2 # tests/functional/test_runner.py:1215\n'
' Given the variable "X" holds 2 # tests/functional/test_runner.py:1221\n'
'\n'
' Scenario: multiplication changing the value # tests/functional/bg_features/simple/simple.feature:9\n'
' Given the variable "X" is equal to 2 # tests/functional/test_runner.py:1215\n'
' Given the variable "X" is equal to 2 # tests/functional/test_runner.py:1221\n'
'\n'
'1 feature (1 passed)\n'
'1 scenario (1 passed)\n'
......@@ -1264,12 +1270,12 @@ def test_output_background_with_success_colorful():
'\033[1;37m I want to automate its test \033[1;30m# tests/functional/bg_features/simple/simple.feature:4\033[0m\n'
'\n'
'\033[1;37m Background:\033[0m\n'
'\033[1;30m Given the variable "X" holds 2 \033[1;30m# tests/functional/test_runner.py:1250\033[0m\n'
'\033[A\033[1;32m Given the variable "X" holds 2 \033[1;30m# tests/functional/test_runner.py:1250\033[0m\n'
'\033[1;30m Given the variable "X" holds 2 \033[1;30m# tests/functional/test_runner.py:1256\033[0m\n'
'\033[A\033[1;32m Given the variable "X" holds 2 \033[1;30m# tests/functional/test_runner.py:1256\033[0m\n'
'\n'
'\033[1;37m Scenario: multiplication changing the value \033[1;30m# tests/functional/bg_features/simple/simple.feature:9\033[0m\n'
'\033[1;30m Given the variable "X" is equal to 2 \033[1;30m# tests/functional/test_runner.py:1250\033[0m\n'
'\033[A\033[1;32m Given the variable "X" is equal to 2 \033[1;30m# tests/functional/test_runner.py:1250\033[0m\n'
'\033[1;30m Given the variable "X" is equal to 2 \033[1;30m# tests/functional/test_runner.py:1256\033[0m\n'
'\033[A\033[1;32m Given the variable "X" is equal to 2 \033[1;30m# tests/functional/test_runner.py:1256\033[0m\n'
'\n'
'\033[1;37m1 feature (\033[1;32m1 passed\033[1;37m)\033[0m\n'
'\033[1;37m1 scenario (\033[1;32m1 passed\033[1;37m)\033[0m\n'
......
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