[英]How to mock database for testing in xUnit?
I have the following DbContext
:我有以下
DbContext
:
public class OrganizerDbContext : IdentityDbContext<AppUser>
{
public OrganizerDbContext(DbContextOptions<OrganizerDbContext> options)
: base(options)
{
}
// list of dbSet<> here
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<AppUser>()
.HasOne(a => a.Accesses)
.WithOne(a => a.User)
.HasForeignKey<UserAccess>(a => a.UserId);
builder.Entity<AppUser>()
.HasOne(a=>a.EmploymentStatus)
.WithOne(a=>a.User)
.HasForeignKey<EmploymentStatus>(a => a.UserId);
builder.Entity<EmploymentStatus>()
.HasOne(a=>a.Facility)
.WithMany(a=>a.Employments)
.HasForeignKey(a => a.FacilityId);
}
}
In my xUnit test, I used FakeItEasy
and have following code:在我的 xUnit 测试中,我使用
FakeItEasy
并具有以下代码:
[Fact]
public async Task AnnouncerIndex_Test_1()
{
// Arrange
var fakeContext = A.Fake<OrganizerDbContext>();
var fakeUserManager = A.Fake<UserManager<AppUser>>();
var controller = new AnnouncementsController(fakeContext, fakeUserManager);
// Act
var result = await controller.IsUserBlockedFromAccesingAnnouncer();
// Assert
Assert.False(result);
}
The test fails and I get this in test details summary:测试失败,我在测试详细信息摘要中得到了这个:
Message: FakeItEasy.Core.FakeCreationException: Failed to create fake of type Organizer3.Data.OrganizerDbContext: Below is a list of reasons for failure per attempted constructor: Constructor with signature (Microsoft.EntityFrameworkCore.DbContextOptions
1[Organizer3.Data.OrganizerDbContext]) failed: No constructor matches the passed arguments for constructor. An exception of type System.InvalidOperationException was caught during this call. Its message was: The DbContextOptions passed to the OrganizerDbContextProxy constructor must be a DbContextOptions<OrganizerDbContextProxy>. When registering multiple DbContext types, make sure that the constructor for each context type has a DbContextOptions<TContext> parameter rather than a non-generic DbContextOptions parameter. at Microsoft.EntityFrameworkCore.DbContext..ctor(DbContextOptions options) at Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserContext
消息:FakeItEasy.Core.FakeCreationException:无法创建 Organizer3.Data.OrganizerDbContext 类型的伪造:以下是每个尝试的构造函数失败的原因列表:具有签名的构造函数 (Microsoft.EntityFrameworkCore.DbContextOptions
1[Organizer3.Data.OrganizerDbContext]) failed: No constructor matches the passed arguments for constructor. An exception of type System.InvalidOperationException was caught during this call. Its message was: The DbContextOptions passed to the OrganizerDbContextProxy constructor must be a DbContextOptions<OrganizerDbContextProxy>. When registering multiple DbContext types, make sure that the constructor for each context type has a DbContextOptions<TContext> parameter rather than a non-generic DbContextOptions parameter. at Microsoft.EntityFrameworkCore.DbContext..ctor(DbContextOptions options) at Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserContext
1[Organizer3.Data.OrganizerDbContext]) failed: No constructor matches the passed arguments for constructor. An exception of type System.InvalidOperationException was caught during this call. Its message was: The DbContextOptions passed to the OrganizerDbContextProxy constructor must be a DbContextOptions<OrganizerDbContextProxy>. When registering multiple DbContext types, make sure that the constructor for each context type has a DbContextOptions<TContext> parameter rather than a non-generic DbContextOptions parameter. at Microsoft.EntityFrameworkCore.DbContext..ctor(DbContextOptions options) at Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserContext
1[Organizer3.Data.OrganizerDbContext]) failed: No constructor matches the passed arguments for constructor. An exception of type System.InvalidOperationException was caught during this call. Its message was: The DbContextOptions passed to the OrganizerDbContextProxy constructor must be a DbContextOptions<OrganizerDbContextProxy>. When registering multiple DbContext types, make sure that the constructor for each context type has a DbContextOptions<TContext> parameter rather than a non-generic DbContextOptions parameter. at Microsoft.EntityFrameworkCore.DbContext..ctor(DbContextOptions options) at Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserContext
5..ctor(DbContextOptions options) at Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityDbContext8..ctor(DbContextOptions options) at Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityDbContext
3..ctor(DbContextOptions options) at Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityDbContext1..ctor(DbContextOptions options) at Organizer3.Data.OrganizerDbContext..ctor(DbContextOptions
1 options) in C:\Users\Smokiel\Desktop\Organizer3\Organizer3\Areas\Identity\Data\OrganizerDbContext.cs:line 15 at Castle.Proxies.OrganizerDbContextProxy..ctor(IInterceptor[], DbContextOptions`1 options)1[Organizer3.Data.OrganizerDbContext]) failed: No constructor matches the passed arguments for constructor. An exception of type System.InvalidOperationException was caught during this call. Its message was: The DbContextOptions passed to the OrganizerDbContextProxy constructor must be a DbContextOptions<OrganizerDbContextProxy>. When registering multiple DbContext types, make sure that the constructor for each context type has a DbContextOptions<TContext> parameter rather than a non-generic DbContextOptions parameter. at Microsoft.EntityFrameworkCore.DbContext..ctor(DbContextOptions options) at Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserContext
5..ctor(DbContextOptions 选项)在 Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityDbContext8..ctor(DbContextOptions options) at Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityDbContext
3..ctor(DbContextOptions 选项)在 Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityDbContext1..ctor(DbContextOptions options) at Organizer3.Data.OrganizerDbContext..ctor(DbContextOptions
1 选项)中C:\Users\Smokiel\Desktop\Organizer3\Organizer3\Areas\Identity\Data\OrganizerDbContext.cs: 第 15 行在 Castle.Proxies.OrganizerDbContextProxy..ctor(IInterceptor[], DbContextOptions`1 选项)Stack Trace: FailedCreationResult.get_Result() line 82 FakeAndDummyManager.CreateFake(Type typeOfFake, Action`1 optionsBuilder, LoopDetectingResolutionContext resolutionContext) line 42 FakeAndDummyManager.CreateFake(Type typeOfFake, LoopDetectingResolutionContext resolutionContext) line 28 A.FakeT line 31 AnnouncementsControllerTests.AnnouncerIndex_Test_1() line 28 --- End of stack trace from previous location ---
堆栈跟踪:FailedCreationResult.get_Result() 第 82 行 FakeAndDummyManager.CreateFake(类型 typeOfFake,Action`1 optionsBuilder,LoopDetectingResolutionContext resolutionContext)第 42 行 FakeAndDummyManager.CreateFake(类型 typeOfFake,LoopDetectingResolutionContext resolutionContext)第 28 行 A.FakeT 第 31 行 AnnouncementsControllerTests.AnnouncerIndex_Test_1() 28 --- 上一个位置的堆栈跟踪结束 ---
I tried adding empty constructor by adding public OrganizerDbContext() { }
to DbContext, after running test again i got this summary:我尝试通过将
public OrganizerDbContext() { }
添加到 DbContext 来添加空构造函数,再次运行测试后我得到了这个摘要:
Message: System.ArgumentException: Object 'Organizer3.Controllers.AnnouncementsController' of type Organizer3.Controllers.AnnouncementsController is not recognized as a fake object. Stack Trace: DefaultFakeManagerAccessor.GetFakeManager(Object proxy) line 28 Fake.GetFakeManager(Object fakedObject) line 28 FakeConfigurationManager.GuardAgainstNonFake(Object target) line 83 FakeConfigurationManager.CallTo[T](Expression`1 callSpecification) line 45 A.CallTo[T](Expression`1 callSpecification) line 161 AnnouncementsControllerTests.AnnouncerIndex_Test_1() line 34 --- End of stack trace from previous location ---
消息:System.ArgumentException:Object Organizer3.Controllers.AnnouncementsController 类型的“Organizer3.Controllers.AnnouncementsController”未被识别为伪造的 object。堆栈跟踪:DefaultFakeManagerAccessor.GetFakeManager(对象代理)第 28 行 Fake.GetFakeManager(对象伪造的对象)第 28 行FakeConfigurationManager.GuardAgainstNonFake(Object target) 第 83 行 FakeConfigurationManager.CallTo[T](Expression`1 callSpecification) 第 45 行 A.CallTo[T](Expression`1 callSpecification) 第 161 行 AnnouncementsControllerTests.AnnouncerIndex_Test_1() 第 34 行 --- 堆栈结束从以前的位置跟踪 ---
I expected to get a dummy context I could use for testing, it wasn't called anywhere outside of controller constructor, and I can't get it running.我希望得到一个可以用于测试的虚拟上下文,它没有在 controller 构造函数之外的任何地方调用,而且我无法运行它。
as the error indicates如错误所示
A.Fake<OrganizerDbContext>();
Would not pass the parameters which are required to the constructor of DbContext不会将所需的参数传递给 DbContext 的构造函数
you have to pass DbContextOptions<> to the contructor of the dbcontext like below您必须将 DbContextOptions<> 传递给 dbcontext 的构造函数,如下所示
A.Fake<WebApplication6Context>(x => x.WithArgumentsForConstructor(new object[] { options }));
I tried as below,hopes could help:我试过如下,希望能有所帮助:
The Action in controller: controller 中的操作:
public List<SomeEntity> GetEntities()
{
return _context.SomeEntity.ToList();
}
The Dbcontext:数据库上下文:
public class WebApplication6Context : DbContext
{
public WebApplication6Context (DbContextOptions<WebApplication6Context> options)
: base(options)
{
}
public virtual DbSet<WebApplication6.Models.SomeEntity>? SomeEntity { get; set; }
}
Codes related with Test测试相关代码
[Fact]
public void Test1()
{
var data = new List<SomeEntity>() { new SomeEntity() { Id = 1, Name = "N1" }, new SomeEntity() { Id = 2, Name = "N2" } }.AsQueryable();
var fakeDbSet = A.Fake<DbSet<SomeEntity>>(x=>
{
x.Implements(typeof(IQueryable<SomeEntity>));
x.Implements(typeof(IEnumerable<SomeEntity>));
});
A.CallTo(() => ((IQueryable<SomeEntity>)fakeDbSet).GetEnumerator()).Returns(data.GetEnumerator());
var fakecontext = A.Fake<WebApplication6Context>(x =>
{
x.WithArgumentsForConstructor(new object[] { new DbContextOptionsBuilder<WebApplication6Context>().Options });
});
A.CallTo(() => fakecontext.SomeEntity).Returns(fakeDbSet);
var controller = new SomeEntitiesController(fakecontext);
//Act
var result=controller.GetEntities();
//Assert
Assert.Equal(2,result.Count);
}
The Result:结果:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.