我试图在我的测试用例中自动模拟ApiController类.当我使用WebApi1时,它工作得很好.我开始在新项目中使用WebApi2,并且在尝试运行新测试后抛出此异常:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Security.Cryptography.CryptographicException: pCertContext is an invalid handle.
at System.Security.Cryptography.CAPI.CertSetCertificateContextProperty(SafeCertContextHandle pCertContext, UInt32 dwPropId, UInt32 dwFlags, SafeLocalAllocHandle safeLocalAllocHandle)
at System.Security.Cryptography.X509Certificates.X509Certificate2.set_Archived(Boolean value)
Run Code Online (Sandbox Code Playgroud)
我的测试代码:
[Theory, AutoMoqData]
public void approparte_status_code_is_returned(
string privateKey,
UsersController sut)
{
var response = sut.GetUser(privateKey);
var result = response;
Assert.Equal(HttpStatusCode.OK, result.StatusCode);
}
Run Code Online (Sandbox Code Playgroud)
如果我手动创建sut,测试用例确实有效:
[Theory, AutoMoqData]
public void approparte_status_code_is_returned(
string privateKey,
[Frozen]Mock<IUserModel> stubModel)
{
var sut = new UsersController(stubModel.Object);
var response = sut.GetUser(privateKey);
var result = response;
Assert.Equal(HttpStatusCode.OK, result.StatusCode);
} …Run Code Online (Sandbox Code Playgroud) 代码:
IFixture fixture = new Fixture().Customize(new AutoMoqCustomization());
fixture.Customize<ViewDataDictionary>(c => c.Without(x => x.ModelMetadata));
var target = fixture.CreateAnonymous<MyController>();
Run Code Online (Sandbox Code Playgroud)
例外:
System.Reflection.TargetInvocationException:System.Reflection.TargetInvocationException:调用目标已抛出异常.---> System.NotImplementedException:未实现方法或操作.
MyController() 需要3个参数.
我试着在答案中描述的修复在这里,但它是行不通的.
将AutoFixture与AutoFixture.AutoMoq包一起使用时,我有时会发现没有配置为正确测试他们要测试的东西的测试,但由于默认(松散)模拟行为,问题从未被发现:
public interface IService
{
bool IsSomethingTrue(int id);
}
void Main()
{
var fixture = new Fixture()
.Customize(new AutoMoqCustomization());
var service = fixture.Freeze<Mock<IService>>();
Console.WriteLine(service.Object.IsSomethingTrue(1)); // false
}
Run Code Online (Sandbox Code Playgroud)
我想让Mocks用严格的行为创建,所以我们被迫调用Setup()我们期望被调用的方法.我可以为每个单独的模拟这样做:
fixture.Customize<Mock<IService>>(c => c.FromFactory(() => new Mock<IService>(MockBehavior.Strict)));
Run Code Online (Sandbox Code Playgroud)
但是在梳理了AutoMoqCustomization()的源代码以及各种ISpecimenBuilder其他实现之后,我很遗憾只能让所有的Mocks用严格的行为进行初始化.该框架看起来非常灵活和可扩展,所以我确信有一种简单的方法可以做到这一点 - 我无法弄清楚如何做到这一点.
我最近开始使用AutoFixture + AutoMoq,我正在尝试创建一个实例Func<IDbConnection>(即连接工厂).
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var connectionFactory = fixture.Create<Func<IDbConnection>>();
Run Code Online (Sandbox Code Playgroud)
这看起来效果很好:
IDbConnectionCreateCommand,这将让我嘲笑IDbCommandExecuteReader,这将让我嘲笑IDataReader我现在想在模拟上执行其他设置IDataReader,例如让它true在Read()调用时返回.
从我所读到的,我应该Freeze用于此:
var dataReaderMock = fixture.Freeze<Mock<IDataReader>>();
dataReaderMock.Setup(dr => dr.Read())
.Returns(true);
Run Code Online (Sandbox Code Playgroud)
这似乎不符合我的期望.当我打电话时IDbCommand.ExecuteReader,我会得到一个与我刚冻结/设置的读者不同的读者.
这是一个例子:
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var dataReaderMock = fixture.Freeze<Mock<IDataReader>>();
dataReaderMock.Setup(dr => dr.Read())
.Returns(true);
//true - Create<IDataReader> retrieves the data reader I just mocked
Assert.AreSame(dataReaderMock.Object, fixture.Create<IDataReader>());
//false - IDbCommand returns a different …Run Code Online (Sandbox Code Playgroud) 我正在使用 Moq 以异步方法模拟存储库。此方法必须调用 2 次。在第一次调用此方法时,我需要获取空值。其次,我需要获取一些参数。如果此方法不是异步的,那么我可以使用
autoMockContext
.Mock<IPopulationReadRepository>()
.SetupSequence(method => method.GetCityForNewClients(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.Returns(null)
.Returns(new Population { Id = 100, CityLongName = "Kharkiv, Kharkivska, Slobozhanshina" });
Run Code Online (Sandbox Code Playgroud)
所以最后一行出现错误。结果必须是这样的:
autoMockContext
.Mock<IPopulationReadRepository>()
.Setup(method => method.GetCityForNewClients(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.Returns(null);
autoMockContext
.Mock<IPopulationReadRepository>()
.Setup(method => method.GetCityForNewClients(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.ReturnsAsync(new Entities.Zonning.Population { Id = 100, CityLongName = "Kharkiv, Kharkivska, Slobozhanshina" });
Run Code Online (Sandbox Code Playgroud)
但是我一次调用就需要它?
我让 xUnit/Moq/AutoFixture 成功地协同工作,以便我可以通过测试方法输入参数自动模拟对象。我创建了一个[AutoMoqData]在每次测试中使用的自定义属性。这是该属性的代码:
using System.Linq;
using AutoFixture;
using AutoFixture.AutoMoq;
using AutoFixture.Xunit2;
namespace Shared.TestResources.AutoFixture
{
public class AutoMoqDataAttribute : AutoDataAttribute
{
public AutoMoqDataAttribute() : base(() => new Fixture().Customize(new CompositeCustomization(new AutoMoqCustomization(), new SupportMutableValueTypesCustomization())))
{
this.Fixture.Behaviors.OfType<ThrowingRecursionBehavior>().ToList().ForEach(b => Fixture.Behaviors.Remove(b));
this.Fixture.Behaviors.Add(new OmitOnRecursionBehavior());
}
}
}
Run Code Online (Sandbox Code Playgroud)
这有效,但我收到以下编译警告:warning CS0618: 'AutoDataAttribute.Fixture' is obsolete: 'Fixture is created lazily for the performance efficiency, so this property is deprecated as it activates the fixture immediately. If you need to customize the fixture, do that in the factory method …
我正在使用AutoFixture AutoMoqCustomization并尝试创建一个包含readonly属性的类的实例,因此:
public override ILog Logger { get; } = LogManager.GetLogger(typeof(MyService));
Run Code Online (Sandbox Code Playgroud)
这个想法是我应该能够ILog使用以下方法冻结我的测试测试:
var log = fixture.Freeze<Mock<ILog>>;
Run Code Online (Sandbox Code Playgroud)
并验证它在主方法调用之后被调用:
log.Verify(l => l.Warn, Times.Once);
Run Code Online (Sandbox Code Playgroud)
但是,当我调用fixture.Create<MyService>AutoFixture时,不会Logger使用模拟替换属性ILog.我也试图消除默认值LogManager.GetLogger<etc>在这种情况下的价值ILog是null.
其他属性正确填充测试双精度但不是这一个.
作为参考,该ILog接口来自ServiceStack的日志框架,如下所示:
public interface ILog
{
bool IsDebugEnabled { get; }
void Debug(object message);
void Debug(object message, Exception exception);
void DebugFormat(string format, params object[] args);
void Error(object message);
void Error(object message, Exception exception);
void ErrorFormat(string format, params object[] args);
void Fatal(object …Run Code Online (Sandbox Code Playgroud) 我想探索我们是否可以通过设置 AutoMoq 创建的所有 Moq-mock 默认返回 Fixture 创建的值作为方法返回值来节省时间。
在进行如下测试时,这将是有益的:
[TestMethod]
public void Client_Search_SendsRestRequest()
var client = fixture.Create<Client>();
// Could be removed by implementing the mentioned functionality
Mock.Of(JsonGenerator).Setup(j => j.Search(It.IsAny<string>())).Returns(create("JsonBody")));
client.Search(fixture.Create("query"));
Mock.Of(client.RestClient).Verify(c => c.Execute(It.IsAny<RestRequest>()));
Mock.Of(client.RestClient).Verify(c => c.Execute(It.Is<RestRequest>(r => record(r.Body) == record(client.JsonGenerator.Search(query)))));
}
Run Code Online (Sandbox Code Playgroud)
请注意,生成的值必须缓存在 (?) 代理中,我们希望“冻结”相同的值以进行检查。此外,设置模拟Setup应该覆盖创建的值。
那么,我们如何修改 AutoMoq 模拟来做到这一点?
验证它是否有效的简单测试可能是:
[TestMethod]
public void MockMethodsShouldReturnCreatedValues()
{
Guid.Parse(new Fixture().Create<ITest>().Test());
}
public interface ITest
{
string Test();
}
Run Code Online (Sandbox Code Playgroud) 更新: AutoFixture团队在3.51版本中发布了此修复程序.
只需扩展AutoDataAttribute这样做:
public class AutoDataFixedNameAttribute : AutoDataAttribute
{
public AutoDataFixedNameAttribute()
{
this.TestMethodBuilder = new FixedNameTestMethodBuilder();
}
}
Run Code Online (Sandbox Code Playgroud)
然后AutoData在NUnit测试中使用此新属性而不是内置属性.
上一篇文章
我正在尝试将AutoFixture与NUnit和Moq一起使用,使用以下AutoMoqDataAttribute:
public class AutoMoqDataAttribute : AutoDataAttribute
{
public AutoMoqDataAttribute()
: base(new Fixture().Customize(new AutoMoqCustomization()))
{
}
}
Run Code Online (Sandbox Code Playgroud)
但是当我运行这个测试时:
[Test, AutoMoqData]
public void Test(Mock<IUser> user)
{
// do stuff with user
}
Run Code Online (Sandbox Code Playgroud)
测试永远不会运行.正确命中了AutomMoqData,但测试中的代码永远不会执行,所有内容都会在没有任何警告的情况下结束,并显示以下消息:
Test adapter sent back a result for an unknown test case. Ignoring result for 'Test(Mock<Sandbox.IUser>)'
Run Code Online (Sandbox Code Playgroud)
该测试也未出现在测试运行器列表中.
但是,如果我删除参数: …
public interface IResult
{
bool Success { get; }
}
public interface IResult<T> : IResult
{
}
Run Code Online (Sandbox Code Playgroud)
使用AutoFixure和AutoMoq 无论是什么类型,我都试图找到一种Success始终如一的方法.注册假货很容易,但似乎并不适用trueTIResultIResult<T>
automoq ×10
autofixture ×9
moq ×8
c# ×6
unit-testing ×2
.net ×1
automocking ×1
generics ×1
nunit ×1
xunit ×1