我正在使用一个使用 BDD 方法 (SpecFlow)、C# 和 ExtentReports 进行报告的测试框架。
我对我的步骤使用软断言以便能够继续执行。问题是本地 FAILING 的测试用例在范围报告中被标记为 PASSED。我如何为步骤定义 FAILED 设置状态,以便在范围报告中看到测试用例也被标记为 FAILED?这是我的 SofAssert 类:
public static class SoftAssert {
private static readonly ThreadLocal<List<string>> _assertionsMessages = new ThreadLocal<List<string>>();
public static void Add(Action action) {
_assertionsMessages.Value ? ?=new List < string > ();
try {
action.Invoke();
}
catch(Exception exception) {
_assertionsMessages.Value.Add(exception.Message);
LogError(exception.Message);
}
}
public static void AssertAll() {
Logger.Info("-----------Test Finished-----------");
if (_assertionsMessages.Value == null || _assertionsMessages.Value.Count == 0) return;
var messages = new List < string > (_assertionsMessages.Value);
_assertionsMessages.Value.Clear();
throw new AssertionException(messages);
}
private static void LogError(string message)
{
Logger.Fatal("ERROR => !!!!!!");
Logger.Fatal($" {message}");
Logger.Fatal(" !!!!!!");
}
}
这里是断言异常:
public class AssertionException : NUnit.Framework.AssertionException
{
public AssertionException(List<string> assertsMessages) : base($"\nAsserts fails:\n{GetFormattedLog(assertsMessages)}")
{
}
private static string GetFormattedLog(List<string> assertsMessages)
{
var stringBuilder = new StringBuilder();
assertsMessages.ForEach(message => stringBuilder.AppendLine(message));
return stringBuilder.ToString();
}
}
这是我在 BaseTest 类中的钩子:
[BeforeFeature]
public static void BeforeFeature(FeatureContext featureContext)
{
_featureName = _extentReporter.CreateTest<Feature>(featureContext.FeatureInfo.Title);
}
[BeforeScenario]
public void BeforeScenario()
{
_scenarioName = _featureName.CreateNode < Scenario > (_scenarioContext.ScenarioInfo.Title);
}
[AfterStep]
public void InsertReportingSteps()
{
var stepType = _scenarioContext.StepContext.StepInfo.StepDefinitionType.ToString();
if (_scenarioContext.TestError == null)
{
switch (stepType)
{
case "Given":
_scenarioName.CreateNode<Given>(_scenarioContext.StepContext.StepInfo.Text);
break;
case "When":
_scenarioName.CreateNode<When>(_scenarioContext.StepContext.StepInfo.Text);
break;
case "Then":
_scenarioName.CreateNode<Then>(_scenarioContext.StepContext.StepInfo.Text);
break;
case "And":
_scenarioName.CreateNode<And>(_scenarioContext.StepContext.StepInfo.Text);
break;
}
}
else if (_scenarioContext.TestError != null)
{
switch (stepType)
{
case "Given":
_scenarioName.CreateNode<Given>(_scenarioContext.StepContext.StepInfo.Text).Fail(_scenarioContext.TestError.Message);
break;
case "When":
_scenarioName.CreateNode<When>(_scenarioContext.StepContext.StepInfo.Text).Fail(_scenarioContext.TestError.Message);
break;
case "Then":
_scenarioName.CreateNode<Then>(_scenarioContext.StepContext.StepInfo.Text).Fail(_scenarioContext.TestError.Message);
break;
case "And":
_scenarioName.CreateNode<And>(_scenarioContext.StepContext.StepInfo.Text).Fail(_scenarioContext.TestError.Message);
break;
}
}
else if (_scenarioContext.ScenarioExecutionStatus.ToString().Equals("StepDefinitionPending"))
{
switch (stepType)
{
case "Given":
_scenarioName.CreateNode<Given>(_scenarioContext.StepContext.StepInfo.Text).Skip("Step Definition Pending");
break;
case "When":
_scenarioName.CreateNode<When>(_scenarioContext.StepContext.StepInfo.Text).Skip("Step Definition Pending");
break;
case "Then":
_scenarioName.CreateNode<Then>(_scenarioContext.StepContext.StepInfo.Text).Skip("Step Definition Pending");
break;
case "And":
_scenarioName.CreateNode<And>(_scenarioContext.StepContext.StepInfo.Text).Skip("Step Definition Pending");
break;
}
}
}
[AfterScenario]
public static void TearDownReport()
{
try
{
SoftAssert.AssertAll();
}
finally
{
try
{
_extentReporter.Flush();
}
catch (InvalidOperationException e)
{
//ignored
}
}
}
测试是:
[When(@"Get Alert")]
public void WhenTheFirstNumberIsAdded()
{
var alert = _Client.GetAlert();
// Making the test to FAIL. Checking status code equal to 400
SoftAssert.Add(() => alert.SuccessModel.StatusCode.Should().Be(400));
}