模拟实体框架数据库

时间:2011-05-22 12:16:08

标签: c# database entity-framework mocking

我正在使用Entity Framework 4 +。

是否可以使用一些随机数据从架构中自动创建一些MOCK数据库?在整合,放入整数,字符串,放置一些GUID或其他......

这将有助于我调试我的应用程序。

谢谢James,

5 个答案:

答案 0 :(得分:2)

我发现this great tool与EF 4一起用于模拟数据库。基本上它只是一个T4模板,可以创建“普通”EF层,还可以创建一个可用于测试的模拟对象和接口。更多文档here

但是,有一点需要注意。开箱即用它不适合我,因为我的存储库代码调用SaveChanges()和其他未在生成的接口中实现的方法。通过从Microsoft的ObjectContext实现中提取接口并创建自己的IObjectContext接口,我能够解决这个问题。然后我创建了一个基类(用于模拟),它通过简单地将每个调用委托给一个注入的模拟来实现这个接口。这样我可以使用Moq在我的测试类中创建该部分,同时仍然保留在生成的模拟中跟踪插入,更新和删除的功能。

以下是我对“Context”T4模板的更改以解决此问题。很抱歉这样做的一点点零碎 - 所以我没有让我发布整个代码清单,因为它太长了。

fileManager.Process();

之前添加此代码
fileManager.StartNewFile( "IObjectContext.cs");
WriteHeader();
WriteHeaderIncludeSystem();
WriteHeaderIncludeData();
WriteHeaderIncludeContainers();
WriteNamespaceBegin( code, namespaceName );
WriteObjectContextInterface( container, code );
WriteNamespaceEnd( namespaceName );

fileManager.StartNewFile( container.Name + "Mock.ObjectContext.cs");
WriteHeader();
WriteHeaderIncludeSystem();
WriteHeaderIncludeData();
WriteHeaderIncludeContainers();
WriteNamespaceBegin( code, namespaceName );
WriteObjectContextMockBase( container, code );
WriteNamespaceEnd( namespaceName );

WriteInterface()阻止后添加此代码。

<#+
void WriteObjectContextInterface( EntityContainer container, CodeGenerationTools code )
{
#>
/// <summary>
/// The interface for the generic object context. This contains all of
/// the <code>ObjectContext</code> properties that are implemented in the 
/// concrete ObjectContext class. This interface was created so these members
/// can be mocked, as ObjectContext doesn't have a default public constructor.
/// </summary>
<#=Accessibility.ForType(container)#> interface IObjectContext : IDisposable
{
    void AcceptAllChanges();
    void AddObject(string entitySetName, object entity);
    TEntity ApplyCurrentValues<TEntity>(string entitySetName, TEntity currentEntity) where TEntity : class;
    TEntity ApplyOriginalValues<TEntity>(string entitySetName, TEntity originalEntity) where TEntity : class;
    void ApplyPropertyChanges(string entitySetName, object changed);
    void Attach(System.Data.Objects.DataClasses.IEntityWithKey entity);
    void AttachTo(string entitySetName, object entity);
    int? CommandTimeout { get; set; }
    DbConnection Connection { get; }
    ObjectContextOptions ContextOptions { get; }
    void CreateDatabase();
    string CreateDatabaseScript();
    EntityKey CreateEntityKey(string entitySetName, object entity);
    T CreateObject<T>() where T : class;
    ObjectSet<TEntity> CreateObjectSet<TEntity>() where TEntity : class;
    ObjectSet<TEntity> CreateObjectSet<TEntity>(string entitySetName) where TEntity : class;
    void CreateProxyTypes(IEnumerable<Type> types);
    ObjectQuery<T> CreateQuery<T>(string queryString, params ObjectParameter[] parameters);
    bool DatabaseExists();
    string DefaultContainerName { get; set; }
    void DeleteDatabase();
    void DeleteObject(object entity);
    void Detach(object entity);
    void DetectChanges();
    void Dispose();
    int ExecuteFunction(string functionName, params ObjectParameter[] parameters);
    ObjectResult<TElement> ExecuteFunction<TElement>(string functionName, params ObjectParameter[] parameters);
    ObjectResult<TElement> ExecuteFunction<TElement>(string functionName, MergeOption mergeOption, params ObjectParameter[] parameters);
    int ExecuteStoreCommand(string commandText, params object[] parameters);
    ObjectResult<TElement> ExecuteStoreQuery<TElement>(string commandText, params object[] parameters);
    ObjectResult<TEntity> ExecuteStoreQuery<TEntity>(string commandText, string entitySetName, MergeOption mergeOption, params object[] parameters);
    object GetObjectByKey(System.Data.EntityKey key);
    void LoadProperty(object entity, string navigationProperty);
    void LoadProperty(object entity, string navigationProperty, MergeOption mergeOption);
    void LoadProperty<TEntity>(TEntity entity, Expression<Func<TEntity, object>> selector);
    void LoadProperty<TEntity>(TEntity entity, Expression<Func<TEntity, object>> selector, MergeOption mergeOption);
    System.Data.Metadata.Edm.MetadataWorkspace MetadataWorkspace { get; }
    ObjectStateManager ObjectStateManager { get; }
    void Refresh(RefreshMode refreshMode, IEnumerable collection);
    void Refresh(RefreshMode refreshMode, object entity);
    int SaveChanges();
    int SaveChanges(bool acceptChangesDuringSave);
    int SaveChanges(SaveOptions options);
    ObjectResult<TElement> Translate<TElement>(DbDataReader reader);
    ObjectResult<TEntity> Translate<TEntity>(DbDataReader reader, string entitySetName, MergeOption mergeOption);
    bool TryGetObjectByKey(EntityKey key, out object value);
}
<#+
}
#>

<#+
void WriteObjectContextMockBase( EntityContainer container, CodeGenerationTools code )
{
#>
/// <summary>
/// The default concrete implementation of IObjectContext that will be used for mocking. 
/// This contains all of the <code>IObjectContext</code> members that are implemented in the 
/// concrete ObjectContext class. This class was created so these members
/// can be mocked.
/// </summary>
<#=Accessibility.ForType(container)#> abstract class ObjectContextMockBase : IObjectContext
{
    private readonly IObjectContext _objectContext;
    public ObjectContextMockBase(IObjectContext objectContext)
    {
        if (objectContext == null)
            throw new System.ArgumentNullException("objectContext");
        _objectContext = objectContext;
    }

    public virtual void AcceptAllChanges()
    {
        _objectContext.AcceptAllChanges();
    }

    public virtual void AddObject(string entitySetName, object entity)
    {
        _objectContext.AddObject(entitySetName, entity);
    }

    public virtual TEntity ApplyCurrentValues<TEntity>(string entitySetName, TEntity currentEntity) 
        where TEntity : class
    {
        return _objectContext.ApplyCurrentValues<TEntity>(entitySetName, currentEntity);
    }

    public virtual TEntity ApplyOriginalValues<TEntity>(string entitySetName, TEntity originalEntity) 
        where TEntity : class
    {
        return ApplyOriginalValues<TEntity>(entitySetName, originalEntity);
    }

    public virtual void ApplyPropertyChanges(string entitySetName, object changed)
    {
        _objectContext.ApplyPropertyChanges(entitySetName, changed);
    }

    public virtual void Attach(System.Data.Objects.DataClasses.IEntityWithKey entity)
    {
        _objectContext.Attach(entity);
    }

    public virtual void AttachTo(string entitySetName, object entity)
    {
        _objectContext.AttachTo(entitySetName, entity);
    }

    public virtual int? CommandTimeout
    {
        get { return _objectContext.CommandTimeout; }
        set { _objectContext.CommandTimeout = value; }
    }

    public virtual DbConnection Connection 
    { 
        get { return _objectContext.Connection; }
    }

    public virtual ObjectContextOptions ContextOptions
    { 
        get { return _objectContext.ContextOptions; }
    }

    public virtual void CreateDatabase()
    {
        _objectContext.CreateDatabase();
    }

    public virtual string CreateDatabaseScript()
    {
        return _objectContext.CreateDatabaseScript();
    }

    public virtual EntityKey CreateEntityKey(string entitySetName, object entity)
    {
        return _objectContext.CreateEntityKey(entitySetName, entity);
    }

    public virtual T CreateObject<T>() 
        where T : class
    {
        return _objectContext.CreateObject<T>();
    }

    public virtual ObjectSet<TEntity> CreateObjectSet<TEntity>()
        where TEntity : class
    {
        return _objectContext.CreateObjectSet<TEntity>();
    }

    public virtual ObjectSet<TEntity> CreateObjectSet<TEntity>(string entitySetName) 
        where TEntity : class
    {
        return _objectContext.CreateObjectSet<TEntity>(entitySetName);
    }

    public virtual void CreateProxyTypes(IEnumerable<Type> types)
    {
        _objectContext.CreateProxyTypes(types);
    }

    public virtual ObjectQuery<T> CreateQuery<T>(string queryString, params ObjectParameter[] parameters)
    {
        return _objectContext.CreateQuery<T>(queryString, parameters);
    }

    public virtual bool DatabaseExists()
    {
        return _objectContext.DatabaseExists();
    }

    public virtual string DefaultContainerName
    {
        get { return _objectContext.DefaultContainerName; }
        set { _objectContext.DefaultContainerName = value; }
    }

    public virtual void DeleteDatabase()
    {
        _objectContext.DeleteDatabase();
    }

    public virtual void DeleteObject(object entity)
    {
        _objectContext.DeleteObject(entity);
    }

    public virtual void Detach(object entity)
    {
        _objectContext.Detach(entity);
    }

    public virtual void DetectChanges()
    {
        _objectContext.DetectChanges();
    }

    public virtual void Dispose()
    {
        _objectContext.Dispose();
    }

    public virtual int ExecuteFunction(string functionName, params ObjectParameter[] parameters)
    {
        return _objectContext.ExecuteFunction(functionName, parameters);
    }

    public virtual ObjectResult<TElement> ExecuteFunction<TElement>(string functionName, params ObjectParameter[] parameters)
    {
        return _objectContext.ExecuteFunction<TElement>(functionName, parameters);
    }

    public virtual ObjectResult<TElement> ExecuteFunction<TElement>(string functionName, MergeOption mergeOption, params ObjectParameter[] parameters)
    {
        return _objectContext.ExecuteFunction<TElement>(functionName, mergeOption, parameters);
    }

    public virtual int ExecuteStoreCommand(string commandText, params object[] parameters)
    {
        return _objectContext.ExecuteStoreCommand(commandText, parameters);
    }

    public virtual ObjectResult<TElement> ExecuteStoreQuery<TElement>(string commandText, params object[] parameters)
    {
        return _objectContext.ExecuteStoreQuery<TElement>(commandText, parameters);
    }

    public virtual ObjectResult<TEntity> ExecuteStoreQuery<TEntity>(string commandText, string entitySetName, MergeOption mergeOption, params object[] parameters)
    {
        return _objectContext.ExecuteStoreQuery<TEntity>(commandText, entitySetName, mergeOption, parameters);
    }

    public virtual object GetObjectByKey(EntityKey key)
    {
        return _objectContext.GetObjectByKey(key);
    }

    public virtual void LoadProperty(object entity, string navigationProperty)
    {
        _objectContext.LoadProperty(entity, navigationProperty);
    }

    public virtual void LoadProperty(object entity, string navigationProperty, MergeOption mergeOption)
    {
        _objectContext.LoadProperty(entity, navigationProperty, mergeOption);
    }

    public virtual void LoadProperty<TEntity>(TEntity entity, Expression<Func<TEntity, object>> selector)
    {
        _objectContext.LoadProperty<TEntity>(entity, selector);
    }

    public virtual void LoadProperty<TEntity>(TEntity entity, Expression<Func<TEntity, object>> selector, MergeOption mergeOption)
    {
        _objectContext.LoadProperty<TEntity>(entity, selector, mergeOption);
    }

    public virtual System.Data.Metadata.Edm.MetadataWorkspace MetadataWorkspace
    {
        get { return _objectContext.MetadataWorkspace; }
    }

    public virtual ObjectStateManager ObjectStateManager
    {
        get { return _objectContext.ObjectStateManager; }
    }

    public virtual void Refresh(RefreshMode refreshMode, IEnumerable collection)
    {
        _objectContext.Refresh(refreshMode, collection);
    }

    public virtual void Refresh(RefreshMode refreshMode, object entity)
    {
        _objectContext.Refresh(refreshMode, entity);
    }

    public virtual int SaveChanges()
    {
        return _objectContext.SaveChanges();
    }

    public virtual int SaveChanges(bool acceptChangesDuringSave)
    {
        return _objectContext.SaveChanges(acceptChangesDuringSave);
    }

    public virtual int SaveChanges(SaveOptions options)
    {
        return _objectContext.SaveChanges(options);
    }

    public virtual ObjectResult<TElement> Translate<TElement>(DbDataReader reader)
    {
        return _objectContext.Translate<TElement>(reader);
    }

    public virtual ObjectResult<TEntity> Translate<TEntity>(DbDataReader reader, string entitySetName, MergeOption mergeOption)
    {
        return _objectContext.Translate<TEntity>(reader, entitySetName, mergeOption);
    }

    public virtual bool TryGetObjectByKey(EntityKey key, out object value)
    {
        return _objectContext.TryGetObjectByKey(key, out value);
    }
}
<#+
}
#>

WriteMockContextBody()(评论后)的前两行(第二行是大括号)更改为

<#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#>Mock : ObjectContextMockBase, I<#=code.Escape(container)#>
{
    public <#=code.Escape(container)#>Mock(IObjectContext objectContext)
        : base(objectContext)
    {
    }

WriteInterface()的第一行(在评论之后)更改为

<#=Accessibility.ForType(container)#> interface I<#=code.Escape(container)#> : IObjectContext

我还应该注意到,我还没有做过多少测试,但我确实做了一些基本的验证,以确保它的功能。

答案 1 :(得分:0)

这是有助于生成测试数据的库 - http://autopoco.codeplex.com/

答案 2 :(得分:0)

请参阅Rab Hallett的博客,标题为ADO.NET Mocking Context Generator: Visual Studio 2010 Template

这里Rab使用T4模板为EF创建界面。

答案 3 :(得分:-1)

您可以查看有关Visual Studio for Database Professionals的this thread。或者RedGate有一个similar tool。我不知道有任何免费工具可以做到这一点。

答案 4 :(得分:-1)

转到此链接并查看本节“在自动创建的数据库中播种初始数据”

http://weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx