测试使用基于Session的不同数据库的类库

时间:2012-07-19 14:44:43

标签: asp.net entity-framework unit-testing httpcontext

我有一个ASP.NET网站项目,直到最近在App_Code文件夹中有所有代码。它使用Entity Framework 4作为ORM。应用程序分为三个“部分”(假设每个客户一个)。每个部分都有自己的数据库(但是相同的模式)。这是由于性能原因,数据库超过10GB,每行有数百万行。

每次创建context对象时,都会调用一个保存部分ID的Session变量,并为此上下文选择专有连接字符串。

看起来像这样(以下是静态Connection类的成员):

public static MyEntities GetEntityContext()
{
    if (HttpContext.Current.Session["section"] == null)
    {
        HttpContext.Current.Response.Redirect("~/Login.aspx");
    }
    var context = new MyEntities(GetEntityConnectionStringForSection((int)HttpContext.Current.Session["section"]);
    return context;
}

private static string GetEntityConnectionStringForSection(int section)
{
    switch (section)
    {
        case 1: return ConfigurationManager.ConnectionStrings["entity_1"].ConnectionString;
        case 2: return ConfigurationManager.ConnectionStrings["entity_2"].ConnectionString;
        case 3: return ConfigurationManager.ConnectionStrings["entity_3"].ConnectionString;
        default: return ConfigurationManager.ConnectionStrings["entity_1"].ConnectionString;
    }
}

它非常好用,并且每次执行任何数据访问时会话超时的情况也会处理。

最近,由于我需要在两个网站之间共享数据库类,我将所有数据库类移动到单独的类库和引用的System.Web库,我知道这是不好的做法,但它正在运行。

现在下一步是包含单元和模块测试,当我在库中使用HttpContext时很难或不可能,所以我想摆脱System.Web引用。这种情况的最佳做法是什么?

我想我不能只将HttpContext传递给GetEntityContext(),因为它也是从我的实体类中调用的。虽然这可能是重构的。也许这就是我应该去的地方?

我也想知道是否有可能以某种方式将当前部分ID传递给整个库?它不能只是静态属性,因为据我所知,使用该应用程序的所有用户都会这样做。这应该是用户特定的。

重申目标是在不失去透明连接字符串选择和会话超时处理的情况下进行自动化测试。

如果我在这个阶段做了一些根本性的错误,请告诉我。我明天早上可以再看一下这个问题(UTC时间早上8点),所以请不要因为我的沉默而气馁。

编辑:

库中Connection类的使用示例:

public partial class Store
{
    public static List<Store> GetSpecialStores()
    {
        using (var context = Connection.GetEntityContext())
        {
          return context.Stores.Where(qq => qq.Type > 0).OrderBy(qq => qq.Code).ToList();
        }
    }
}

1 个答案:

答案 0 :(得分:1)

您可以在库中声明接口IContextProvider并使用它来检索上下文。类似的东西:

public interface IContextProvider
{
   MyEntities GetEntityContext();
}

这将使您的图书馆可测试。在您的Web项目中,您可以将IContextProvider实现注入您的库中。

public class WebContextProvider : IContextProvider
{
    public MyEntities GetEntityContext()
    {
        if (HttpContext.Current.Session["section"] == null)        
            HttpContext.Current.Response.Redirect("~/Login.aspx");

        int sectionId = (int)HttpContext.Current.Session["section"];
        string connectionString = GetEntityConnectionStringForSection(sectionId);
        var context = new MyEntities(connectionString);
        return context;
    }

   private static string GetEntityConnectionStringForSection(int section)
   {
       switch (section)
       {
          case 1: return ConfigurationManager.ConnectionStrings["entity_1"].ConnectionString;
          case 2: return ConfigurationManager.ConnectionStrings["entity_2"].ConnectionString;
          case 3: return ConfigurationManager.ConnectionStrings["entity_3"].ConnectionString;
          default: return ConfigurationManager.ConnectionStrings["entity_1"].ConnectionString;
       }
   }
}

将此接口注入存储库或其他数据访问类。

public partial class Store
{
    private IContextProvider contextProvider;

    public Store(IContextProvider contextProvider)
    {
        this.contextProvider = contextProvider;
    }

    public List<Store> GetSpecialStores()
    {
        using (var context = contextProvider.GetEntityContext())
        {
          return context.Stores.Where(qq => qq.Type > 0).OrderBy(qq => qq.Code).ToList();
        }
    }
}