Ответ 1
NUnit 3 добавляет метод Assert.Multiple
и атрибут MultipleAsserts
.
В тесте, который содержит некоторые утверждения, например:
Assert.AreEqual(1,1);
Assert.AreEqual(2,1);
Assert.AreEqual(2,2);
Возможно ли, чтобы тест продолжал работать после сбоя в какой-то момент? В этом примере первое условие истинно, второе не выполняется, и тест останавливается. Я также хотел бы оценить следующее условие.
NUnit 3 добавляет метод Assert.Multiple
и атрибут MultipleAsserts
.
Я предпочитаю быть практичным и ставить несколько связанных утверждений одним методом.
У меня есть вспомогательный класс, который позволяет использовать следующий синтаксис (я использую):
AssertAll.Succeed(
() => Assert.AreEqual("bb", id.Context),
() => Assert.AreEqual("abc", id.FullName),
() => Assert.AreEqual("b", id.SessionID));
который дает мне сообщения об ошибках следующим образом:
Assert.AreEqual failed. Expected:<bb>. Actual:<b\c>.
Assert.AreEqual failed. Expected:<abc>. Actual:<[b\c]a{103}>.
at FXP_COM.Tests.EnumToStringConverterterTests.<>c__DisplayClass3.<ShouldConvert>b__0() in UnitTest1.cs: line 31
at FXP_COM.Tests.AssertAll.Succeed(Action[] assertions) in UnitTest1.cs: line 46 at FXP_COM.Tests.AssertAll.Succeed(Action[] assertions) in UnitTest1.cs: line 62
at FXP_COM.Tests.EnumToStringConverterterTests.ShouldConvert() in UnitTest1.cs: line 30
а вспомогательный класс следующий:
using System;
using NUnit.Framework;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
public static class AssertAll
{
public static void Succeed(params Action[] assertions)
{
var errors = new List<Exception>();
foreach (var assertion in assertions)
try
{
assertion();
}
catch (Exception ex)
{
errors.Add(ex);
}
if (errors.Any())
{
var ex = new AssertionException(
string.Join(Environment.NewLine, errors.Select(e => e.Message)),
errors.First());
// Use stack trace from the first exception to ensure first
// failed Assert is one click away
ReplaceStackTrace(ex, errors.First().StackTrace);
throw ex;
}
}
static void ReplaceStackTrace(Exception exception, string stackTrace)
{
var remoteStackTraceString = typeof(Exception)
.GetField("_remoteStackTraceString",
BindingFlags.Instance | BindingFlags.NonPublic);
remoteStackTraceString.SetValue(exception, stackTrace);
}
}
Нет. Обычно в этой ситуации вы помещаете весь код выше утверждений в метод настройки, а затем записываете каждое утверждение в свой собственный тестовый пример.
Нет, вы не можете сделать это с помощью NUnit. Вы должны сделать что-то вроде @Константин Спирин. Я создал небольшое расширение, которое вы можете использовать; он называется NUnit-GroupAssert. Его можно найти здесь: https://github.com/slvnperron/NUnit-GroupAssert
Как использовать его:
[Test]
public void Verify_GroupsExceptions()
{
var group = new AssertGroup();
group.Add(() => Assert.AreEqual(10, 20));
group.Add(() => Assert.AreEqual(1, 1));
group.Add(() => Assert.AreEqual(3, 4));
group.Add(() => Assert.IsTrue(1 > 3));
group.Verify();
}
// OR
public void Verify_GroupsExceptions()
{
// Verifies on disposal
using (var group = new AssertGroup())
{
group.Add(() => Assert.AreEqual(10, 20));
group.Add(() => Assert.AreEqual(1, 1));
group.Add(() => Assert.AreEqual(3, 4));
group.Add(() => Assert.IsTrue(1 > 3));
}
}
он выведет:
Тест завершился неудачно, потому что не удалось выполнить одно или несколько утверждений:
1) Ожидается: 10
Но было: 20
Из Verify_GroupsExceptions в строке 182) Ожидается: 3
Но было: 4
Из Verify_GroupsExceptions в строке 203) Ожидается: Истинный
Но было: False
Из Verify_GroupsExceptions в строке 21
Неа. В любом случае у вас не должно быть более одного утверждения за каждый тест, что уменьшает разделение и затрудняет определение того, какой из них не удалось.
Если у вас есть много кода, который необходимо выполнить перед утверждением, выделите его в функцию [SetUp] или сделайте его отдельной процедурой.
Вы можете немного обмануть и на самом деле не сработать в данной точке, а скорее пометить для отказа, а затем провалиться в самом конце, что-то вроде следующего:
var sbError = new StringBuilder();
if (!SomeCondition()) {
sbError.AppendLine("SomeCondition failed");
}
if (!SomeOtherCondition()) {
sbError.AppendLine("SomeOtherCondition failed");
}
Assert.AreEqual(0, sbError.Length, sbError.ToString());
Я бы не рекомендовал этого, но если вам нужно сделать это один или два раза, это не должно быть так уж плохо.
Запускает исключение NUnit.Framework.AssertionException, если они терпят неудачу. Вы можете поймать это исключение во втором утверждении, оценить третье утверждение, а затем повторно выбросить исключение.
Не то, что я рекомендовал бы, по причинам, указанным Эд Вудкоком и Карлом Манастером.
Вы можете перестроить свой тест, чтобы обернуть утверждения в блок try/catch и отслеживать их для последующей проверки. Однако я не рекомендую это делать. Вы действительно должны использовать отдельные тесты для каждого условия, если вы хотите, чтобы они были протестированы независимо.
bool[] assertionSuccesses = new bool[] { false, false, false };
try
{
Assert.AreEqual( 1, 1 );
assertionSuccesses[0] = true;
}
catch (AssertionException) {}
...
if (assertionSuccesses.Any( s => !s ))
{
Assert.Fail("one of the assertions failed");
}
Я переписал образец кода Константина Спирина в VB.
Imports NUnit.Framework
Imports System.Reflection
Public Class Group_LIB_NUnit_Assert_Multiple
Public Shared Sub Multiple(ParamArray Assertions As Action())
Dim ExceptionObj As Exception
Dim Exceptions As New List(Of Exception)
Dim Message As String
For Each Assertion In Assertions
Try
Assertion()
Catch ex As Exception
Exceptions.Add(ex)
End Try
Next
If Exceptions.Count > 0 Then
Message = String.Format("{0}{1} assertions failed: {2}{3}", Environment.NewLine, Exceptions.Count, Environment.NewLine, String.Join(Environment.NewLine, Exceptions.Select(Function(e) e.Message).ToList()))
ExceptionObj = New AssertionException(Message)
StackTraceReplace(ExceptionObj, Exceptions.First.StackTrace)
Throw ExceptionObj
End If
End Sub
Public Shared Sub StackTraceReplace(ExceptionObj As Exception, StackTrace As String)
Dim RemoteStackTraceString As FieldInfo
RemoteStackTraceString = GetType(Exception).GetField("_remoteStackTraceString", Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic)
RemoteStackTraceString.SetValue(ExceptionObj, StackTrace)
End Sub
End Class
Imports Group.Library4
Imports NUnit.Framework
<TestFixture()> _
Public Class TEST_Group_LIB_NUnit_Assert_Multiple
<Test()> _
<TestCaseSource("Factory")> _
Public Sub Multiple(TestObj As TEST_DATA_Group_LIB_NUnit_Assert_Multiple)
Group_LIB_NUnit_Assert_Multiple.Multiple(Sub() Assert.That(TestObj.Gender, [Is].EqualTo("F"c), "Gender"), Sub() Assert.That(TestObj.Name, [Is].EqualTo("George Washington"), "Name"))
End Sub
Public Function Factory() As List(Of TEST_DATA_Group_LIB_NUnit_Assert_Multiple)
Dim L As New List(Of TEST_DATA_Group_LIB_NUnit_Assert_Multiple)
Dim TestObj As TEST_DATA_Group_LIB_NUnit_Assert_Multiple
TestObj = New TEST_DATA_Group_LIB_NUnit_Assert_Multiple()
TestObj.DOB = New DateTime(2015, 8, 12)
TestObj.Gender = "M"c
TestObj.Name = "Abraham Lincoln"
L.Add(TestObj)
TestObj = New TEST_DATA_Group_LIB_NUnit_Assert_Multiple()
TestObj.DOB = New DateTime(2015, 8, 12)
TestObj.Gender = "F"c
TestObj.Name = "George Washington"
L.Add(TestObj)
TestObj = New TEST_DATA_Group_LIB_NUnit_Assert_Multiple()
TestObj.DOB = New DateTime(2015, 8, 12)
TestObj.Gender = "A"c
TestObj.Name = "John Hancock"
L.Add(TestObj)
Return L
End Function
End Class
Public Class TEST_DATA_Group_LIB_NUnit_Assert_Multiple
Public Property DOB As Date
Public Property Gender As Char
Public Property Name As String
End Class