.NET core 使用 Xunit + Autofixture + Moq 编写更好的单元测试
.NET core write better unit tests with Xunit + Autofixture + Moq
在用于单元测试的 .NET Core 中,我使用 Xunit、Moq 和 Autofixture。但即使有了它们,我发现我的单元测试变得复杂并且需要时间。
也许有人可以告诉我是否有任何方法可以使这个测试更小?
[Fact]
public async Task Verify_NotAuthorised_NoServiceSendInvoked()
{
// Arrange
var fixture = new Fixture()
.Customize(new AutoMoqCustomization());
var sut = fixture.Create<VerificationService>();
var mockApiBuilder = fixture.Freeze<Mock<IApiEntityBuilder>>();
//init mocked mockSendServiceOne, so later I could check if it was invoked or not
var mockSendServiceOne = fixture.Freeze<Mock<ISendServiceOne>>();
mockApiBuilder.Setup(x => x.Verification(It.IsAny<string>(), It.IsAny<string>()))
.Returns(fixture.Create<VerificationEntity>());
var call = fixture.Freeze<Mock<ISendServiceTwo>>();
call.Setup(x => x.IsSuccessful()).Returns(false);
// Act
await sut.Verify(fixture.Create<string>(), fixture.Create<string>());
// Assert
mockSendServiceOne.Verify(x => x.Call(It.IsAny<SendServiceOneEntity>()), Times.Never);
}
测试方法本身
public async Task<CreatedEntity> Verify(string dataOne, string dataTwo)
{
await _someCaller.Call(_apiEntityBuilder.Verification(dataOne, dataTwo));
_someCaller.CreatePayment();
if (!_someCaller.IsSuccessful()) return _someCaller.CreatedEntity;
await mockSendServiceOne.Call(_apiEntityBuilder.Call(_someCaller.CreatedEntity.SpecificData));
return _someCaller.CreatedEntity;
}
这里我正在测试是否 isSuccessful() returns fasle 然后不应该调用 mockSendServiceOne.Call。
有人可以给我一些关于如何编写更好的单元测试的反馈吗?
因为只是为了这个小的代码检查,我不得不写很多代码来测试它。
您可以使用 AutoData Theories。 (链接到 Mark Seeman 关于这种确切情况的精彩 post)。
简而言之,AutoFixture 有一个名为 AutoData
的内置属性,您可以继承该属性,然后使用 AutoMoqCustomization 自定义夹具。
你用这个属性装饰你的测试方法([Theory]),现在 autofixture 会自动生成你为你的测试方法指定的任何参数。
当您使用 Freeze()
方法生成项目时,您将 [Frozen]
属性放在参数前面。
这是一个如何操作的例子:
public class TheTests
{
[Theory]
[AutoDomainData]
public void Verify_WhatWeWannaTest_CallsTheMethodOnTheDependency([Frozen] Mock<ITheDependency> dependency, WhatWeWannaTest sut)
{
// Act
sut.CallTheDependency();
// Assert
dependency.Verify(x => x.TheMethod());
}
}
// Create a AutoData attribute customized with Moq
public class AutoDomainDataAttribute : AutoDataAttribute
{
public static IFixture FixtureFactory()
{
var f = new Fixture();
// I like members of interfaces to be configured, so i set it her
f.Customize(new AutoMoqCustomization { ConfigureMembers = true });
return f;
}
public AutoDomainDataAttribute() : base(FixtureFactory) { }
}
// Simple class we can test
public class WhatWeWannaTest
{
private readonly ITheDependency _theDependency;
public WhatWeWannaTest(ITheDependency theDependency) { _theDependency = theDependency; }
public void CallTheDependency()
{
_theDependency.TheMethod();
}
}
// Simple dependency for WhatWeWannaTest
public interface ITheDependency
{
int TheMethod();
}
在用于单元测试的 .NET Core 中,我使用 Xunit、Moq 和 Autofixture。但即使有了它们,我发现我的单元测试变得复杂并且需要时间。
也许有人可以告诉我是否有任何方法可以使这个测试更小?
[Fact]
public async Task Verify_NotAuthorised_NoServiceSendInvoked()
{
// Arrange
var fixture = new Fixture()
.Customize(new AutoMoqCustomization());
var sut = fixture.Create<VerificationService>();
var mockApiBuilder = fixture.Freeze<Mock<IApiEntityBuilder>>();
//init mocked mockSendServiceOne, so later I could check if it was invoked or not
var mockSendServiceOne = fixture.Freeze<Mock<ISendServiceOne>>();
mockApiBuilder.Setup(x => x.Verification(It.IsAny<string>(), It.IsAny<string>()))
.Returns(fixture.Create<VerificationEntity>());
var call = fixture.Freeze<Mock<ISendServiceTwo>>();
call.Setup(x => x.IsSuccessful()).Returns(false);
// Act
await sut.Verify(fixture.Create<string>(), fixture.Create<string>());
// Assert
mockSendServiceOne.Verify(x => x.Call(It.IsAny<SendServiceOneEntity>()), Times.Never);
}
测试方法本身
public async Task<CreatedEntity> Verify(string dataOne, string dataTwo)
{
await _someCaller.Call(_apiEntityBuilder.Verification(dataOne, dataTwo));
_someCaller.CreatePayment();
if (!_someCaller.IsSuccessful()) return _someCaller.CreatedEntity;
await mockSendServiceOne.Call(_apiEntityBuilder.Call(_someCaller.CreatedEntity.SpecificData));
return _someCaller.CreatedEntity;
}
这里我正在测试是否 isSuccessful() returns fasle 然后不应该调用 mockSendServiceOne.Call。
有人可以给我一些关于如何编写更好的单元测试的反馈吗? 因为只是为了这个小的代码检查,我不得不写很多代码来测试它。
您可以使用 AutoData Theories。 (链接到 Mark Seeman 关于这种确切情况的精彩 post)。
简而言之,AutoFixture 有一个名为 AutoData
的内置属性,您可以继承该属性,然后使用 AutoMoqCustomization 自定义夹具。
你用这个属性装饰你的测试方法([Theory]),现在 autofixture 会自动生成你为你的测试方法指定的任何参数。
当您使用 Freeze()
方法生成项目时,您将 [Frozen]
属性放在参数前面。
这是一个如何操作的例子:
public class TheTests
{
[Theory]
[AutoDomainData]
public void Verify_WhatWeWannaTest_CallsTheMethodOnTheDependency([Frozen] Mock<ITheDependency> dependency, WhatWeWannaTest sut)
{
// Act
sut.CallTheDependency();
// Assert
dependency.Verify(x => x.TheMethod());
}
}
// Create a AutoData attribute customized with Moq
public class AutoDomainDataAttribute : AutoDataAttribute
{
public static IFixture FixtureFactory()
{
var f = new Fixture();
// I like members of interfaces to be configured, so i set it her
f.Customize(new AutoMoqCustomization { ConfigureMembers = true });
return f;
}
public AutoDomainDataAttribute() : base(FixtureFactory) { }
}
// Simple class we can test
public class WhatWeWannaTest
{
private readonly ITheDependency _theDependency;
public WhatWeWannaTest(ITheDependency theDependency) { _theDependency = theDependency; }
public void CallTheDependency()
{
_theDependency.TheMethod();
}
}
// Simple dependency for WhatWeWannaTest
public interface ITheDependency
{
int TheMethod();
}