我曾经在单元测试中使用 Moq 和 AutoMoqer,但我的团队决定改为 NSubstitute。我们大量使用 DI,因此我希望能够请求一个目标进行测试,并让该目标自动将所有模拟对象提供给其构造函数,或者换句话说,是一个传入模拟的 DI 容器。我还想根据需要修改这些模拟对象。
使用 Moq/AutoMoq/MSTest 的示例
[TestMethod]
public void ReturnSomeMethod_WithDependenciesInjectedAndD1Configured_ReturnsConfiguredValue()
{
const int expected = 3;
var diContainer = new AutoMoq.AutoMoqer();
var mockedObj = diContainer.GetMock<IDependency1>();
mockedObj
.Setup(mock => mock.SomeMethod())
.Returns(expected);
var target = diContainer.Resolve<MyClass>();
int actual = target.ReturnSomeMethod();
Assert.AreEqual(actual, expected);
}
public interface IDependency1
{
int SomeMethod();
}
public interface IDependency2
{
int NotUsedInOurExample();
}
public class MyClass
{
private readonly IDependency1 _d1;
private readonly IDependency2 _d2;
//please imagine this has a bunch of dependencies, …
Run Code Online (Sandbox Code Playgroud) c# unit-testing dependency-injection autofixture nsubstitute
我有一个简单的ViewModel,它包含一些按钮.使用PaP Prism的EventAggregator引发的事件可以更改这些按钮的可见性,这也是此VM的唯一构造函数参数.当我不使用AutoFixture时,相应的测试工作正常.
[Theory]
[InfrastructureAutoData]
public void AllButtonsAreShownWhenVisibilityStatusIsSet(
[Frozen]EventAggregator eventAggregator,
ActionBarViewModel sut)
{
eventAggregator
.GetEvent<ActionButtonActivationEvent>()
.Publish(VisibleActionButtons.All);
sut.CancelButtonVisibility.Should().Be(Visibility.Visible);
sut.BackButtonVisibility.Should().Be(Visibility.Visible);
sut.NextButtonVisibility.Should().Be(Visibility.Visible);
sut.Visiblity.Should().Be(Visibility.Visible);
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,它不像这里给出的那样起作用,因为AutoFixture注入ViewModel的EventAggregator实例是另一个实例,而不是注入测试的实例.
public class InfrastructureAutoData : AutoDataAttribute
{
public InfrastructureAutoData()
{
Initialize();
}
private void Initialize()
{
this.Fixture.Customize(new AutoMoqCustomization());
Fixture.Register<IEventAggregator>(() => new EventAggregator());
}
}
public class ActionBarViewModel
{
public ActionBarViewModel(IEventAggregator eventAggregator)
{
eventAggregator.GetEvent<ActionButtonActivationEvent>()
.Subscribe(ActivateButtons);
ActivateButtons(VisibleActionButtons.None);
}
/// <summary>
/// Visibility of a button which cancels the current action.
/// </summary>
public Visibility CancelButtonVisibility { get; private set; }
/// <summary> …
Run Code Online (Sandbox Code Playgroud) 我正在尝试创建一个在数据中有一些差异的对象列表.诸如字符串之类的类型很好,因为它们每次都是随机的,但是我发现bool在CreateMany()生成的集合中的每个对象中始终是相同的值.
示例类,用于演示:
public class FooBar
{
public string Name { get; set; }
public bool IsFoo { get; set; }
public bool IsBar { get; set; }
}
var fooBars = new Fixture().Build<FooBar>().CreateMany(5).ToList();
// Result
fooBars[0].IsFoo; // true
fooBars[1].IsFoo; // true
fooBars[2].IsFoo; // true
...
Run Code Online (Sandbox Code Playgroud)
可以实现以下目标吗?
// Wanted result
fooBars[0].IsFoo; // true
fooBars[1].IsFoo; // false
fooBars[2].IsFoo; // true
fooBars[3].IsFoo; // false
...
Run Code Online (Sandbox Code Playgroud)
干杯!
我最近将此正则表达式模式属性应用于我的类中的一个属性,以便评估有效的url格式.现在出现的问题是AutoFixture无法创建显示错误的实例
"AutoFixture无法从Ploeh.AutoFixture.Kernel.RegularExpressionRequest创建实例,很可能是因为它没有公共构造函数,是抽象或非公共类型."
我尝试了一些像
var contact = _fixture.Build<ContactEntity>()
.With(c=>c.Customer.Website,
new SpecimenContext(_fixture)
.Resolve(new RegularExpressionRequest(Constants.UrlRegex)))
.Create();
Run Code Online (Sandbox Code Playgroud)
和
public class WebsiteSpecimenBuilder: ISpecimenBuilder
{
public object Create(object request,
ISpecimenContext context)
{
var pi = request as PropertyInfo;
if (pi!=null && pi.PropertyType == typeof(string)
&& (pi.Name.Equals("Email") || pi.Name.Equals("Website")))
{
//tried both of these options
return (new OmitSpecimen() || "http://www.website.com";
}
return new NoSpecimen(request);
}
}
Run Code Online (Sandbox Code Playgroud)
但我仍然无法通过自动混合来创建课程.我错过了要创建它的东西,或者这个正则表达式太复杂,无法自动处理?
例如ISomething
,一个具有三个属性的接口:string Name
和int Count
一些复杂的属性ImComplex
(具有循环依赖性等),我不想自动构建.所以我需要AutoFixture来创建一个Mock of ISomething
with Name
并Count
通过其默认算法设置并ImComplex
为null.但如果我试图像这样解决它我会得到一个例外:
fixture.Customize(new AutoConfiguredMoqCustomization());
var some = fixture.Build<ISomething>().Without(x=>x.ImComplex).Create<ISomething>();
Run Code Online (Sandbox Code Playgroud)
Ploeh.AutoFixture.ObjectCreationException:装饰的ISpecimenBuilder无法根据请求创建样本:RP.Core.IInformationUnit.如果请求表示接口或抽象类,则会发生这种情况; 如果是这种情况,请注册一个可以根据请求创建标本的ISpecimenBuilder.如果在强类型的Build表达式中发生这种情况,请尝试使用其中一个IFactoryComposer方法提供工厂.
我该怎么办?
我正在尝试使用AutoFixture为类生成特定值,但是Builder
给出了一个abstract
类.因此,构建器无法查看具体类型的属性...因此canot /不知道何时/如何创建它们.
例如
public abstract class BaseClass
{
// Common properties.
public string Id { get; set }
public Baa Baa { get; set; }
}
public class ConcreteA : BaseClass
{
public string Name { get; set ;}
}
public class ConcreteB : BaseClass
{
public NumberOfPeople int { get; set }
}
Run Code Online (Sandbox Code Playgroud)
所以,当我创建一个BaseClass的假实例时,我希望在适当的时候设置concete值.
例如
Class | Property and value, to set.
----------------------------------------
ConcreteA | Name = "Jane"
ConcreteB | NumberOfPeople = 3
Run Code Online (Sandbox Code Playgroud)
我不知道如何定义(在Builder …
我想知道在使用设置的测试用例时,在调用受测系统(SUT)的构造函数之前是否存在为依赖项设置模拟的方法AutoData
.
我的SUT看起来像:
class Sut
{
private readonly IFoo foo;
public Sut(IFooFactory factory)
{
this.foo = factory.Build(1, 2);
}
public IFoo Foo
{
get
{
return this.foo;
}
}
}
Run Code Online (Sandbox Code Playgroud)
所以我写的测试看起来像:
[Theory]
[AutoData]
internal void Foo_IsCorrectlySet_Test(
[Frozen] Mock<IFooFactory> fooFactory,
IFoo foo,
Sut sut)
{
fooFactory.Setup(mock => mock.Build(1, 2))
.Returns(foo)
.Verifiable();
var actual = sut.Foo;
Assert.Equal(foo, sut);
fooFactory.Verify();
}
Run Code Online (Sandbox Code Playgroud)
显然,Sut
在我能够设置之前,此测试作为运行的构造函数失败IFooFactory
.所以我想,我可能已经能够的声明改变Sut
,以Lazy<Sut>
测试.但是,在运行实际测试代码之前,构造函数仍然运行,这意味着我的测试将失败.
现在我知道我可以轻松地用一个实际Fixture
对象设置这个测试并手动创建我的所有对象并在我打电话之前设置它们Sut
很好但是我想保持我的测试大致相同因此我'我想知道是否有一种方法,我仍然可以使用AutoData
属性设置我的测试但不运行构造函数,直到所有设置完成后?
我正在寻找一种模拟方法的方法,以便在多次调用时结果是不同的。更具体地说,我要模拟的是方法,以便第三次调用该方法时,我想针对该结果进行断言。
此语法不正确,但是模拟了我想要完成的工作:
var foo = Fixture.Freeze<IFoo>();
foo.Exists(Arg.Any<object>()).Returns("firstcall").SecondCall("secondcall").ThirdCall("thirdcall");
Run Code Online (Sandbox Code Playgroud)
您可以在AutoFixture中执行此操作吗?
编辑:正如马克所指出的,这是一个与NSubstitute有关的问题,而不是与AutoFixture本身有关。我已经更新了标题。
使用AutoFixture我可以使用Create方法轻松创建数据对象的实例,如下所示:
_fixture.Create<FilterItems>()
Run Code Online (Sandbox Code Playgroud)
使用这种技术,我可以保护将来可能出现的构造函数中的任何更改,但它也会填充所有属性,在这种情况下(因为它是一组过滤器)是不需要的.
有没有办法告诉AutoFixture创建对象,但不填写任何属性?
我知道有一个没有方法可以跳过一个字段,但是使用它意味着我必须继续添加它,而我只是从一个空对象开始并在测试需要时添加它.
我正在使用AutoFixture的[AutoData]
属性为POCO实例提供一些单元测试(NUnit)。例如:
[Test, AutoData]
public void Create_NameIsNull_ThrowsException(MyPOCO myPOCO) {..}
Run Code Online (Sandbox Code Playgroud)
我最近在POCO中添加了一个新的字符串属性,该属性必须始终包含格式正确的URL。
自然,[AutoData]
不知道此要求,并为此属性生成通常的基于GUID的字符串值。这导致我的测试失败(因为我已经进行了一些基于数据注释的验证)。
我遵循@ploeh的建议,并编写了基于公约的 AutoFixture 定制,它专门为我的这个新属性生成了格式正确的URL字符串。这是一个UrlSpecimenBuilder
实现的类ISpecimenProvider
。
我的问题是,我如何将新产品ISpecimenProvider
与结合[AutoData]
?
我不想参加fixture.Customizations.Add(new UrlSpecimenBuilder());
每个单元测试。我正在寻找一个将执行相同操作的测试夹具设置步骤。
autofixture ×10
c# ×8
unit-testing ×4
.net ×2
automoq ×2
nsubstitute ×2
interface ×1
moq ×1
regex ×1
xunit.net ×1