Wcf 实体框架5-如何更改单元测试的连接字符串?

Wcf 实体框架5-如何更改单元测试的连接字符串?,wcf,unit-testing,entity-framework-5,ioc-container,Wcf,Unit Testing,Entity Framework 5,Ioc Container,这是我第一次涉足实体框架,我有一个使用EF5和存储库模式的工作项目。我想对实时数据库进行集成测试。我为现有生产数据库创建了一个快照,并编写了一个存储过程,以便在每次运行测试时重新创建一个新的快照。我的问题是,当“处于单元测试模式”时,如何将上下文切换到此数据库快照?在我的app.config中,我的实时和测试连接字符串如下: <connectionStrings> <add name="ReportingDbContext" connectionString="Server

这是我第一次涉足实体框架,我有一个使用EF5和存储库模式的工作项目。我想对实时数据库进行集成测试。我为现有生产数据库创建了一个快照,并编写了一个存储过程,以便在每次运行测试时重新创建一个新的快照。我的问题是,当“处于单元测试模式”时,如何将上下文切换到此数据库快照?在我的app.config中,我的实时和测试连接字符串如下:

<connectionStrings>
  <add name="ReportingDbContext" connectionString="Server=LiveServer;Database=UnifiedReporting;User Id='myuser';Password='mypass';Trusted_Connection=False" providerName="System.Data.SqlClient" />
  <add name="TestingDbContext" connectionString="Server=LiveServer;Database=UnifiedReportingSnapshot;User Id='myuser';Password='mypass';Trusted_Connection=False" providerName="System.Data.SqlClient" />
</connectionStrings>

如果可能的话,我希望将我的连接字符串保存在app.config中,并且在我的NUnit测试WCF服务中的方法的[SetUp]部分期间,能够以某种方式切换到测试连接字符串。

我总是使用一个单独的单元测试项目和自己的app.config。连接字符串与主应用程序中的名称相同,但数据库连接不同

当您运行单元测试时,例如从Visual Studio中运行单元测试时,会在后台执行一个单元测试运行程序,它只是一个具有自己配置的常规应用程序,即app.config

您可以为每个测试启动和处理上下文。大多数单元测试框架都具有将方法标记为安装/拆卸装置的属性,这些装置可以在每个测试装置或每个测试中运行。您可以在测试装置设置中初始化IoC容器(NUnit中的
[TestFixtureSetUp]
)和测试设置中的上下文(NUnit中的
[setup]


对于某些场景,我们使用脚本来确保和恢复数据库状态,但是对于大多数测试,我们在测试设置中启动一个脚本,并在测试拆卸中处理它(不提交)。这可以方便地回滚测试中所做的任何更改,但测试中所做的数据库更改是真实的。

如果您使用的是存储库模式,为什么不直接模拟数据库呢?在阅读了大量关于EF5的问题/答案后,我了解到模拟可能不是最好的方法。这是因为具有真实DB的Linq to实体的行为与具有假DB的Linq to对象的行为不同。使用内存中的DbSet,事情可能会顺利进行,但在真正的交易中失败。我想这取决于。如果您的存储库隐藏了EF,那么如果您不测试存储库代码本身,这并不重要。如果你正在测试你的存储库代码,那么你可能需要一个真正的数据库。我总是使用一个单独的单元测试项目和它自己的app.config。上下文在这两个.Gert中具有相同的名称-如果我在测试项目中使用具有相同名称的不同连接字符串,那么从测试项目中启动ReportingDbContext是否会引用本地app.config?谢谢Gert!为了确保我正确理解TransactionScope,如果不提交对EF上下文/模型的更改,即使我调用.SaveChanges()正确,也不会保存更改?数据库事务是一个独立的整体,将被提交,因为数据库不知道C#TransactionScope,对吗?是的,你是对的。TS范围内发生的一切都必须通过调用
Complete()
显式提交。如果不调用此方法,则不会提交任何内容。这也适用于
SaveChanges
调用。
public class ReportingDbContext : DbContext
{
    public ReportingDbContext() : base("name=ReportingDbContext") // as per my app.config
    {

    }

    // inventory
    public DbSet<ComputerEntity> Computers { get; set; }
    public DbSet<NetworkAdapterEntity> NetworkAdapters { get; set; }
    // ... plus a whole bunch more
}
public interface IUnitOfWork : IDisposable
{
    void Commit();

    // inventory
    IRepository<ComputerEntity> Computers { get; }
    IRepository<NetworkAdapterEntity> NetworkAdapters { get; }
    // ... plus a bunch more
}

public class UnitOfWork : IUnitOfWork
{
    private readonly ReportingDbContext _dbContext = null;

    public UnitOfWork()
    {
        _dbContext = new ReportingDbContext();
    }

    public void Commit()
    {
        _dbContext.SaveChanges();
    }

    // Inventory
    public IRepository<ComputerEntity> Computers {get { return new Repository<ComputerEntity>(_dbContext); }}
    public IRepository<NetworkAdapterEntity> NetworkAdapters { get { return new Repository<NetworkAdapterEntity>(_dbContext); } }
    // ... lots more
}
public interface IRepository<T> where T : class
{
    IQueryable<T> GetAll();
    IQueryable<T> Find(Expression<Func<T, bool>> predicate);
    T GetById(int id);
    void Remove(T entity);
    void Add(T newEntity);
}

public class Repository<T> : IRepository<T> where T : class
{
    protected DbContext DbContext { get; set; }
    protected DbSet<T> DbSet { get; set; }

    public Repository(DbContext dbContext)
    {
        if (dbContext == null)
        {
            throw new ArgumentNullException("dbContext");
        }
        DbContext = dbContext;
        DbSet = DbContext.Set<T>();
    }

    public IQueryable<T> GetAll()
    {
        return DbSet;
    }

 // ... more implementation of the interface, nothing fancy
}
public ComputerDTO GetComputerDetails(string hostname, string client)
{
 // don't worry about the return type, it's defined elsewhere
    using (var uoW = new UnitOfWork())
    {
        var repo = uoW.Computers;
        var computer = repo.Find(x => x.Hostname == hostname && x.CompanyEntity.Name == client).FirstOrDefault();
        // do stuff
    }
}