有没有办法使用FluentAssertions
做这样的事情response.Satisfy(r =>
r.Property1== "something" &&
r.Property2== "anotherthing"));
我试图避免编写多个Assert语句。使用https://sharptestex.codeplex.com/这是可能的,我使用的时间最长。但是SharpTestEx不支持.Net Core。
答案 0 :(得分:9)
您应该能够使用通用Match
断言通过谓词验证主题的多个属性
response.Should()
.Match<MyResponseObject>((x) =>
x.Property1 == "something" &&
x.Property2 == "anotherthing"
);
答案 1 :(得分:3)
以上(匹配)解决方案未返回正确的错误消息。因此,如果您想犯一个很好的错误,并且只断言,那么:
result.Should().BeEquivalentTo(new MyResponseObject()
{
Property1 = "something",
Property2 = "anotherthing"
});
匿名对象
如果您只想检查某些成员,请使用:
result.Should().BeEquivalentTo(new
{
Property1 = "something",
Property2 = "anotherthing"
}, options => options.ExcludingMissingMembers());
小心使用!
注意:上述解决方案为您提供了一条断言。我认为多行断言没有错,只要它在功能上是一个断言即可。
如果因为一次要多个错误而需要这样做,请考虑将多行断言包装在AssertionScope
中。
using (new AssertionScope())
{
result.Property1.Should().Be("something");
result.Property2.Should().Be("anotherthing");
}
如果它们均失败,则上述语句现在将立即给出两个错误。
答案 2 :(得分:1)
为此,我使用了扩展功能,其功能类似于SatisfyRespectively()
:
public static class FluentAssertionsExt {
public static AndConstraint<ObjectAssertions> Satisfy(
this ObjectAssertions parent,
Action<MyClass> inspector) {
inspector((MyClass)parent.Subject);
return new AndConstraint<ObjectAssertions>(parent);
}
}
这是我的用法:
[TestMethod] public void FindsMethodGeneratedForLambda() =>
Method(x => x.Lambda())
.CollectGeneratedMethods(visited: empty)
.Should().ContainSingle().Which
.Should().Satisfy(m => m.Name.Should().Match("<Lambda>*"))
.And.Satisfy(m => m.DeclaringType.Name.Should().Be("<>c"));
[TestMethod] public void FindsMethodGeneratedForClosure() =>
Method(x => x.Closure(0))
.CollectGeneratedMethods(visited: empty)
.Should().HaveCount(2).And.SatisfyRespectively(
fst => fst.Should()
.Satisfy(m => m.Name.Should().Be(".ctor"))
.And.Satisfy(m => m.DeclaringType.Name.Should().Match("<>c__DisplayClass*")),
snd => snd.Should()
.Satisfy(m => m.Name.Should().Match("<Closure>*"))
.And.Satisfy(m => m.DeclaringType.Name.Should().Match("<>c__DisplayClass*")));
不幸的是,由于FluentAssertions的设计,这种方法不能很好地推广,因此您可能必须用不同的类型来提供此方法的多个重载,以代替MyClass
。
我认为,真正正确的方法是为要对其运行此类断言的类型实现*Assertions
类型。该文档提供了an example:
public static class DirectoryInfoExtensions
{
public static DirectoryInfoAssertions Should(this DirectoryInfo instance)
{
return new DirectoryInfoAssertions(instance);
}
}
public class DirectoryInfoAssertions :
ReferenceTypeAssertions<DirectoryInfo, DirectoryInfoAssertions>
{
public DirectoryInfoAssertions(DirectoryInfo instance)
{
Subject = instance;
}
protected override string Identifier => "directory";
public AndConstraint<DirectoryInfoAssertions> ContainFile(
string filename, string because = "", params object[] becauseArgs)
{
Execute.Assertion
.BecauseOf(because, becauseArgs)
.ForCondition(!string.IsNullOrEmpty(filename))
.FailWith("You can't assert a file exist if you don't pass a proper name")
.Then
.Given(() => Subject.GetFiles())
.ForCondition(files => files.Any(fileInfo => fileInfo.Name.Equals(filename)))
.FailWith("Expected {context:directory} to contain {0}{reason}, but found {1}.",
_ => filename, files => files.Select(file => file.Name));
return new AndConstraint<DirectoryInfoAssertions>(this);
}
}
答案 3 :(得分:1)
假设您使用xUnit,则可以通过从正确的基类继承来解决它。无需在测试中更改实现。这是这样的:
public class UnitTest1 : TestBase
{
[Fact]
public void Test1()
{
string x = "A";
string y = "B";
string expectedX = "a";
string expectedY = "b";
x.Should().Be(expectedX);
y.Should().Be(expectedY);
}
}
public class TestBase : IDisposable
{
private AssertionScope scope;
public TestBase()
{
scope = new AssertionScope();
}
public void Dispose()
{
scope.Dispose();
}
}
或者,您可以将期望包装到ValueTuple中。方法如下:
[Fact]
public void Test2()
{
string x = "A";
string y = "B";
string expectedX = "a";
string expectedY = "b";
(x, y).Should().Be((expectedX, expectedY));
}