【问题标题】:How to Mock Breeze.EFContextProvider? UPDATED如何模拟 Breeze.EFContextProvider?更新
【发布时间】:2014-02-04 19:20:18
【问题描述】:
 /*************************** UPDATED *****************/

此后,我尝试继承 EFContextProvider,以便可以将 Context 作为虚拟属性提供以进行测试,并且可以将上下文提供程序注入到我的存储库中。这种新模式确实适用于 IOC,但单元测试仍然失败并出现以下错误:

测试方法 MyProj.Infrastructure.MyItemTests.The_MyRepository_MyItems_Should.Return_A_IQuerable_List_of_MyItem_Instances 抛出异常: System.NullReferenceException:对象引用未设置为对象的实例

/************ * 更新 #2 *******/ 添加了存储库,因此我的示例代码更加清晰。

/********************** THE NEW PATTERN TO SUPPORT IOC ******************************/

public interface IMyDbContextProvider {

    MyDbContext Context { get; }
    string Metadata { get; }
    SaveResult SaveChanges( JObject saveBundle );

}

public class MyDbContext : BaseContext<MyDbContext>, IMyDbContext  {

    public virtual DbSet<MyItem> MyItem{ get; set; }

    protected override void OnModelCreating( DbModelBuilder modelBuilder ) {
        // Use singular table names
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>( );

        // Disable proxy creation and lazy loading; not wanted in this service context.
        Configuration.ProxyCreationEnabled = false;
        Configuration.LazyLoadingEnabled = false;

        modelBuilder.Configurations.Add(new MyItemMap());


    }
}


public class MyContextProvider : EFContextProvider <MyDBContext> , IMyContextProvider {

    public MyContextProvider( ) {

    }
    public virtual MyDbContext Context {
        get { return base.Context; }
    }

    public new string Metadata {
        get {
            return base.Metadata();
        }
    }

    public virtual SaveResult SaveChanges( JObject saveBundle ) {
        return base.SaveChanges( saveBundle );
    }

    protected override bool BeforeSaveEntity( EntityInfo entityInfo ) {
        return base.BeforeSaveEntity( entityInfo );
    }

}

     public interface IMyRepository {

    string Metadata { get; }
    IQueryable<MyItem> GetMyItems{ get; }
    SaveResult SaveChanges( JObject saveBundle );

}
 public class MyRepository : IMyRepository {

    private readonly IMyContextProvider _myContextProvider;

    public MyRepository (IMyContextProvider myContextProvider ) {
        _myContextProvider = myContextProvider;
    }

    public MyDbContext Context {
        get {
            return _myContextProvider.Context;
        }
    }

    public string Metadata {
        get {
            return _myContextProvider.Metadata;
        }
    }

    public SaveResult SaveChanges(JObject saveBundle) {
        return _myContextProvider.SaveChanges( saveBundle );
    }

    public IQueryable<MyItem> GetMyItems() {
        get {
            return Context.MyItems;
        }
    }


}

/**********************My UNIT TEST SET UP FUNCTION AND TEST FUNCTION****/
       [TestInitialize()]
        public void SetUp( ) {
        _querableMyItemData = GetQueryableMyItemData( ); //Returns a list of                  MyItems.AsQueryable()


        _mockMyContextProvider = new Mock<IMyContextProvider>( );

        _mockMyItemSet = new Mock<DbSet<MyItem>>( );
        _mockMyItemSet.As<IQueryable<MyItem>>( ).Setup( m => m.Provider ).Returns( _querableMyItemData.Provider );
        _mockMyItemSet.As<IQueryable<MyItem>>( ).Setup( m => m.Expression ).Returns( _querableMyItemData.Expression );
        _mockMyItemSet.As<IQueryable<MyItem>>( ).Setup( m => m.ElementType ).Returns( _querableMyItemData.ElementType );
        _mockMyItemSet.As<IQueryable<MyItem>>( ).Setup( m => m.GetEnumerator( ) ).Returns( _querableMyItemData.GetEnumerator( ) );


        _mockMyContextProvider.Setup( m => m.Context.Units ).Returns( _mockUnitSet.Object );

    }

    [TestMethod]
    public void Return_A_IQuerable_List_of_MyItem_Instances( ) {
        var expectedType = typeof( IEnumerable<MyItem> );

        var myRepository = new MyRepository( _mockMyContextProvider.Object );

        var resultingMyItems = myRepository.GetMyItems();

        Assert.IsInstanceOfType( resultingMyItems, expectedType );
    }

【问题讨论】:

    标签: c# dependency-injection inversion-of-control breeze repository


    【解决方案1】:

    没有深入观察,我注意到了一些事情。

    首先,您没有告诉我们是什么导致了NullReferenceException。 “对象引用未设置为对象的实例”不是有用的消息,因此我们也无法帮助您。

    其次,您正尝试在MyDbContextProvider 中对基类EFContextProvider 中的非虚拟成员进行虚拟化。你可以证明这些成员应该是虚拟的(我会与你并肩站立......请为此创建一个 UserVoice)。

    但是基类成员不是虚拟的,因此您冒着这样的风险,即沿途一些其他方法将转换为基类 EFContextProvider 并尝试访问未模拟的实现。我不知道您的情况是否会发生这种情况,但这显然是一种可能性。

    第三,如果您的测试设置必须模拟 IQueryable 类的成员(例如,ProviderExpressionElementType),那么您工作太辛苦了。这对于有效测试来说实在是太大了。您需要另一种方法来使您的存储库可测试。

    第四,因为您没有显示存储库(也不要打扰...已经有太多代码了),我不知道 myRepository.myItems 与测试模拟有何关系。

    关于EFContextProvider 太难伪造,你有一个非常好的观点。为了可测试性,它没有正确编写。公平地说,EF 团队并没有提供太多帮助,因为 DbContextObjectContext 看起来也不容易虚拟化。

    但你自己还有其他问题要先追查。

    【讨论】:

    • 您好 Ward,非常感谢您的回复。
    • 添加示例存储库只是为了让我的示例代码更完整。无论如何,我注意到测试设置方法没有 TestInitialize 属性。现在测试通过了。测试的原因是确保我在调用存储库方法 GetMyItems 时从上下文中获取预期的类型。测试这样一个简单的方法有点矫枉过正,它更像是一个概念证明,以便我知道我可以实际测试 Breeze 内容提供程序。
    • 原来只需要模拟 GetEnumerator 来模拟您的 EF6 DbSet。我担心 EFContextProvider 属性是虚拟的,我相信这会及时出现,希望我能帮助把它向前推进 :) Ward,我真的很感谢你的意见!
    猜你喜欢
    • 2017-11-03
    • 2011-02-08
    • 1970-01-01
    • 1970-01-01
    • 2013-02-02
    • 1970-01-01
    • 2011-01-04
    • 2019-12-08
    • 2012-05-25
    相关资源
    最近更新 更多