【问题标题】:Moq Mocking with Identity 2.0 Database使用 Identity 2.0 数据库进行 Moq 模拟
【发布时间】:2014-06-22 10:58:05
【问题描述】:

我成功地在 MVC 5、Entity Framework 6 应用程序中使用 Moq 模拟对我的 BusAct 控制器设置了一个集成测试,该应用程序基于一个简单的成员资格数据库。但现在我已将数据库迁移到 Identity 2.0 并将 UserProfile 替换为 ApplicationUser。

IdentityDbContext:(修改自Simple members DbContext)

  public class MyDb : IdentityDbContext<ApplicationUser> // DbContext  
  {
    public MyDb () : base("MyApplication") { }

    // public virtual DbSet<UserProfile> UserProfiles { get; set; }
    public virtual DbSet<BusAcnt> BusAcnts { get; set; } // marking as virtual allows mocking override
    public virtual DbSet<...>
    ...

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
      base.OnModelCreating(modelBuilder);
      modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
    }
  }

MockDbSetup:

  public class MockDbSetup
  {
    public static Mock<MyDb> MockMyDb()
    {
      var dataBa = new List<BusAcnt>  {
        new BusAcnt {Id = 0, CmpnyName = "Company 1", NmOfc = 1, Status = "Active"},
        new BusAcnt {Id = 1, CmpnyName = "Company 2", NmOfc = 1, Status = "Active"},
        new BusAcnt {Id = 2, CmpnyName = "Company 3", NmOfc = 1, Status = "Active"},
        new BusAcnt {Id = 3, CmpnyName = "Company 4", NmOfc = 1, Status = "Active"},
        new BusAcnt {Id = 4, CmpnyName = "Company 5", NmOfc = 1, Status = "Active"},
        new BusAcnt {Id = 5, CmpnyName = "Company 6", NmOfc = 1, Status = "Active"}
      }.AsQueryable();
      var mockSetBa = new Mock<DbSet<BusAcnt>>();
      mockSetBa.As<IQueryable<BusAcnt>>().Setup(m => m.Provider).Returns(dataBa.Provider);
      mockSetBa.As<IQueryable<BusAcnt>>().Setup(m => m.Expression).Returns(dataBa.Expression);
      mockSetBa.As<IQueryable<BusAcnt>>().Setup(m => m.ElementType).Returns(dataBa.ElementType);
      mockSetBa.As<IQueryable<BusAcnt>>().Setup(m => m.GetEnumerator()).Returns(dataBa.GetEnumerator());
      var MyDb = new Mock<MyDb>();
      mockMyDb.Setup(c => c.BusAcnts).Returns(mockSetBa.Object);
      return mockMyDb;
    }
  }

集成测试:

[Fact]
public void GetAllBusAcnt()
{
  var mockMyDb = MockDBSetup.MockMyDb();
  var controller = new BusAcntController(mockMyDb.Object);
  var controllerContextMock = new Mock<ControllerContext>();
  controllerContextMock.Setup(
      x => x.HttpContext.User.IsInRole(It.Is<string>(s => s.Equals("admin")))
      ).Returns(true);
  controller.ControllerContext = controllerContextMock.Object;

  var viewResult = controller.Index() as ViewResult;
  var model = viewResult.Model as PagedBusIdxModel;

  Assert.NotNull(model);
  Assert.Equal(6, model.BusAcnts.ToList().Count());
  Assert.Equal("Company 2", model.BusAcnts.ToList()[1].CmpnyName);
}

当我现在运行测试时,我得到了这些错误:

System.Data.Entity.ModelConfiguration.ModelValidationExceptionOne or more validation errors were detected during model generation:

Castle.Proxies.IdentityUserRole: : EntityType 'IdentityUserRole' has no key defined. Define the key for this EntityType.
Castle.Proxies.IdentityUserLogin: : EntityType 'IdentityUserLogin' has no key defined. Define the key for this EntityType.
IdentityUserRoles: EntityType: EntitySet 'IdentityUserRoles' is based on type 'IdentityUserRole' that has no keys defined.
IdentityUserLogins: EntityType: EntitySet 'IdentityUserLogins' is based on type 'IdentityUserLogin' that has no keys defined.
   at System.Data.Entity.Core.Metadata.Edm.EdmModel.Validate()
   at System.Data.Entity.DbModelBuilder.Build(DbProviderManifest providerManifest, DbProviderInfo providerInfo)
   at System.Data.Entity.DbModelBuilder.Build(DbConnection providerConnection)
   at System.Data.Entity.Internal.LazyInternalContext.CreateModel(LazyInternalContext internalContext)
   at System.Data.Entity.Internal.RetryLazy`2.GetValue(TInput input)
   at System.Data.Entity.Internal.LazyInternalContext.InitializeContext()
   at System.Data.Entity.Internal.InternalContext.CreateObjectContextForDdlOps()
   at System.Data.Entity.Database.Exists()
   at Microsoft.AspNet.Identity.EntityFramework.IdentityDbContext`1.IsIdentityV1Schema(DbContext db)
   at Microsoft.AspNet.Identity.EntityFramework.IdentityDbContext`1..ctor(String nameOrConnectionString, Boolean throwIfV1Schema)
   at Microsoft.AspNet.Identity.EntityFramework.IdentityDbContext`1..ctor(String nameOrConnectionString)
   at MyApplication.Models.MyDb..ctor() in MyDb.cs: line 9
   at Castle.Proxies.MyDbProxy..ctor(IInterceptor[])

我认为我需要修改 MockDbSetup,但找不到任何有关如何执行此操作的信息。

我尝试添加

  var dataUsr = new List<ApplicationUser>
  {
    new ApplicationUser { UserName = "Test", PasswordHash = "a123cdefg"} }.AsQueryable();
  var mockSetUsr = new Mock<DbSet<ApplicationUser>>();
  mockSetUsr.As<IQueryable<BusAcnt>>().Setup(m => m.Provider).Returns(dataUsr.Provider);
  mockSetUsr.As<IQueryable<BusAcnt>>().Setup(m => m.Expression).Returns(dataUsr.Expression);
  mockSetUsr.As<IQueryable<BusAcnt>>().Setup(m => m.ElementType).Returns(dataUsr.ElementType);
  mockSetUsr.As<IQueryable<BusAcnt>>().Setup(m => m.GetEnumerator()).Returns(dataUsr.GetEnumerator()); 

但我在GetEnumerator 上收到“无法解决”错误

也没有

  mockMyDb.Setup(c => c.AspNetUsers).Returns(mockSetUsr.Object);  

  mockMyDb.Setup(c => c.ApplicationUser).Returns(mockSetUsr.Object);

有效,因为它无法解析AspNetUsersApplicationUser

有没有人知道如何做到这一点,关于模拟 Identity 2.0 数据库的文档链接会特别有用?

【问题讨论】:

标签: unit-testing moq entity-framework-6.1 asp.net-identity-2


【解决方案1】:

虽然可能有一种方法可以让 EF 绕过其内部行为以进行模拟,但迄今为止最简单的方法是使用 IDbSet 而不是 DbSet,并从 MyDb 实例中提取接口。

public interface IMyDb   
{
    IDbSet<BusAcnt> BusAcnts { get; set; } // marking as virtual allows mocking override
    IDbSet<...>

    int SaveChanges();
}

您目前正在做的是部分模拟,我一直认为这是有问题的。我只是避免它。

【讨论】:

    【解决方案2】:

    感谢 Jamie 和 Andreas 在Testing framework says entity has no key defined for built in entity.的回答

    MockDbSetup 中的MockMyDb() 方法中,将{ CallBase = true }; 添加到var MyDb = new Mock&lt;MyDb&gt;(); 导致

    var MyDb = new Mock<MyDb>() { CallBase = true };
    

    【讨论】:

      猜你喜欢
      • 2013-12-23
      • 1970-01-01
      • 1970-01-01
      • 2023-03-29
      • 2014-09-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多