C# 如何使Moq理解类型约束对于已验证的调用是可接受的?
摘要 我目前正在编写一些集成代码,以便与会计系统进行交互 讨论中的会计系统是Acceo Acomba,它使用的SDK变成了分布式COM对象 我已经编写了一个泛型类,用于为任何给定的Acomba实体提供泛型存储库C# 如何使Moq理解类型约束对于已验证的调用是可接受的?,c#,unit-testing,generics,moq,C#,Unit Testing,Generics,Moq,摘要 我目前正在编写一些集成代码,以便与会计系统进行交互 讨论中的会计系统是Acceo Acomba,它使用的SDK变成了分布式COM对象 我已经编写了一个泛型类,用于为任何给定的Acomba实体提供泛型存储库 public abstract class AcombaRepository<TEntity, TNativeRepository> where TEntity : class where TNativeRepository : IBaseDataKey {
public abstract class AcombaRepository<TEntity, TNativeRepository>
where TEntity : class
where TNativeRepository : IBaseDataKey {
public AcombaRepository( TNativeRepository nativeRepository, IMapper entityMapper ) {
// Guard clauses...
NativeRepository = nativeRepository;
this.entityMapper = entityMapper;
}
protected readonly TNativeRepository NativeRepository;
public TEntity Create( TEntity toCreate ) {
NativeRepository.ReserveCardNumber(); // Insert
entityMapper.Map( toCreate, NativeRepository ); // Assigning props
NativeRepository.AddCard(); // Save or commit to Acomba
}
}
公共抽象类存储库
地点:班级
假设地点:Ibakey{
公共Acomba存储库(TNativeRepository nativeRepository,IMapper entityMapper){
//保护条款。。。
NativeRepository=NativeRepository;
this.entityMapper=entityMapper;
}
受保护的只读存储本地存储;
公共触角创建(触角创建){
NativeRepository.ReserveCardNumber();//插入
entityMapper.Map(toCreate,NativeRepository);//分配道具
NativeRepository.AddCard();//保存或提交到Acomba
}
}
iBakey
此接口是系统中任何给定可访问实体的基本实体。为了确保我能够访问它的基础知识,我在我的泛型存储库中设置了这个类型约束
AcombaProductsRepository
这是实际使用基本方法的测试代码
public class AcombaProductsRepository : AcombaRepository<MyProduct, IProduct022> {
public AcombaPRoductsRepository( IProduct022 nativeRepository, IMapper productMapper )
: base( nativeRepository, productMapper ) {
}
}
公共类ACOMBAProducts存储库:AcombaRepository{
公共AcombaPRoductsRepository(IPProduct022 nativeRepository,IMapper productMapper)
:base(nativeRepository,productMapper){
}
}
单元测试
为了确保我的代码充分使用Acomba SDK在Acomba底层数据存储中创建新实体,我验证了某些步骤是否得到严格遵守
public class AcombaProductsRepositoryTests {
private readonly Mock<IProduct022> nativeRepositoryMock;
private readonly AcombaProductsRepsoitory sut;
public AcombaProductsRepositoryTests() {
nativeRepositoryMock = new Mock<IProduct022>();
sut = new AcombaProductsRepository( nativeRepositoryMock.Object );
}
[Fact]
public void Create_Should_Reserve_A_Card_Number() {
var toCreate = new MyProduct();
nativeRepositoryMock.Setup( r => r.ReserveCardNumber() ).Verifiable();
sut.Create( toCreate );
nativeRepositoryMock.Verify( r => r.ReserveCardNumber() );
}
}
公共类AcombaProductsRepositoryTests{
私有只读Mock nativeRepositoryMock;
私有只读ACOMBAProductsRepository sut;
公共AcombaProductsRepositoryTests(){
nativeRepositoryMock=新Mock();
sut=新AcombaProductsRepository(nativeRepositoryMock.Object);
}
[事实]
公共作废创建\应\保留\卡号(){
var toCreate=new MyProduct();
nativeRepositoryMock.Setup(r=>r.ReserveCardNumber()).Verifiable();
sut.Create(创建);
验证(r=>r.ReserveCardNumber());
}
}
在这里,尽管接口IProduct022
源自iBasTakey
,但Moq声明预期调用
IPProduct022.保留卡号
iBakey.ReserveCardNumber
ReserveCardNumber
,实际上执行的调用是否也执行并不重要
如何通过此测试?
更多详细信息(编辑) 下面是来自测试结果的错误消息。
据我所知,Moq执行基本
iBakey
类的调用,而不是IProduct022
派生类的调用,因为类型约束,我怀疑。下面的最小示例是基于提供的OP使用的
public class AcombaProductsRepository : AcombaRepository<MyProduct, IProduct022> {
public AcombaProductsRepository(IProduct022 nativeRepository)
: base(nativeRepository) {
}
}
public abstract class AcombaRepository<TEntity, TNativeRepository>
where TEntity : class
where TNativeRepository : IBaseDataKey {
public AcombaRepository(TNativeRepository nativeRepository) {
NativeRepository = nativeRepository;
}
protected readonly TNativeRepository NativeRepository;
public TEntity Create(TEntity toCreate) {
NativeRepository.ReserveCardNumber(); // Insert
NativeRepository.AddCard(); // Save or commit to Acomba
return toCreate;
}
}
以下测试基于OP中提供的信息,并使用MSTest和最新版本的Moq进行
[TestClass]
public class AcombaProductsRepositoryTests {
private readonly Mock<IProduct022> nativeRepositoryMock;
private readonly AcombaProductsRepository sut;
public AcombaProductsRepositoryTests() {
nativeRepositoryMock = new Mock<IProduct022>();
sut = new AcombaProductsRepository(nativeRepositoryMock.Object);
}
[TestMethod]
public void _Create_Should_Reserve_A_Card_Number() {
//Arrange
var toCreate = new MyProduct();
nativeRepositoryMock.Setup(r => r.ReserveCardNumber()).Verifiable();
//Act
sut.Create(toCreate);
//Asert
nativeRepositoryMock.Verify(r => r.ReserveCardNumber());
}
}
[TestClass]
公共类ACOMBA产品存储测试{
私有只读Mock nativeRepositoryMock;
私有只读ACOMBAProducts存储sut;
公共AcombaProductsRepositoryTests(){
nativeRepositoryMock=新Mock();
sut=新AcombaProductsRepository(nativeRepositoryMock.Object);
}
[测试方法]
公共作废(创建)(应保留)(卡号){
//安排
var toCreate=new MyProduct();
nativeRepositoryMock.Setup(r=>r.ReserveCardNumber()).Verifiable();
//表演
sut.Create(创建);
//阿塞特
验证(r=>r.ReserveCardNumber());
}
}
练习时的测试毫无例外地通过了
我建议对原始代码进行审查,因为目前提出的问题是不可复制的 提供一个可用于重现问题的。目前没有足够的详细信息,因此如果
nativeepositorymock.Setup()
已经是.Verifiable()
,那么在断言过程中需要做的就是nativeepositorymock.Verify()代码>将验证所有可验证的设置。@感谢您的反馈。我知道.Verify()
这件事,但我想特别验证这个调用,因为我正在进行单元测试。我发现,因为我在整个测试中为不同的方法调用设置了mock,所以我需要检查是否只执行了这个调用。显示测试中的代码,以便可以使用它来重现问题。如果我们不能运行相同的代码并遇到相同的问题,我们就不能提供太多帮助。这样我们就可以找到原因和解决办法。同样需要一个问题,否则这个问题只会脱离主题。@Nkosi在基本存储库和派生存储库中编辑了测试中的代码,以访问产品实体。
[TestClass]
public class AcombaProductsRepositoryTests {
private readonly Mock<IProduct022> nativeRepositoryMock;
private readonly AcombaProductsRepository sut;
public AcombaProductsRepositoryTests() {
nativeRepositoryMock = new Mock<IProduct022>();
sut = new AcombaProductsRepository(nativeRepositoryMock.Object);
}
[TestMethod]
public void _Create_Should_Reserve_A_Card_Number() {
//Arrange
var toCreate = new MyProduct();
nativeRepositoryMock.Setup(r => r.ReserveCardNumber()).Verifiable();
//Act
sut.Create(toCreate);
//Asert
nativeRepositoryMock.Verify(r => r.ReserveCardNumber());
}
}