Asp.net mvc异步控制器方法测试

时间:2015-02-06 01:08:37

标签: c# asp.net-mvc entity-framework

我一直在尝试学习单元测试,而不是TDD,我试图在我的控制器中单元测试方法。我有Unity 3.5,Asp.Net MVC 5.1,实体框架6.1.2,MS测试,NSubstitute 1.8.1.0和Visual Studio 2013 Update 3.我有一个包含3个项目的解决方案,一个是普通的MVC 5项目,一个单元测试项目和一个类库都正确引用,工作正常。我的代码编译正常,一切都很顺利。我现在正在尝试测试我的异步索引操作,其中存在我的问题。我跟着关于EF6测试的msdn文档,所以我有一个我从Context创建的接口,并在我的控制器中使用它,如下所示:

public interface ITestContext : IDisposable
{
    IDbSet<Account> Accounts { get; set; }
    IDbSet<Bank> Banks { get; set; }
    DbEntityEntry Entry(object o);
    int SaveChanges();
    Task<int> SaveChangesAsync();
}

然后我的上下文类是这样的:

public class TestContext : DbContext, ITestContext
{
    public TestContext(): base("DefaultConnection"){}

    public virtual IDbSet<Account> Accounts { get; set; }
    public virtual IDbSet<Bank> Banks { get; set; }

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

    public override Task<int> SaveChangesAsync()
    {
        return base.SaveChangesAsync();
    }

    public DbEntityEntry Entity(object o)
    {
        return base.Entry(o);
    }
}

所以我使用DI在我的控制器中使用接口。我的所有控制器方法都是异步方法,因此我的索引操作如下所示:

public class AccountsController : Controller
{
    private ITestContext db;

    public AccountsController(ITestContext _db)
    {
        db = _db;
        //db1 = bnk;
    }

    // GET: Accounts
    public async Task<ActionResult> Index()
    {
        var accounts = db.Accounts.Include(a => a.Bank);
        return View(await accounts.ToListAsync());
    }

我创建了一个TestDbAsyncEnumerator和TestDbAsyncQueryProvider,从NSubstitute DbSet / IQueryable<T>获取提示。所以烦人的事情是为了测试这个索引方法该怎么办?这就是我走了多远:

[TestMethod]
    public async Task TestingIndexControllerAction()
    {
        var testdb = new List<Account>
        {
            new Account{ Bank=new Bank{Name="Zenith"}, AccountBalance=19000, AccountName="John Doe"}
        }.AsQueryable();
        var test = Substitute.For<IDbSet<Account>, IDbAsyncEnumerable<Account>>().Initailize(testdb);
        var context = Substitute.For<ITestContext>();
        context.Accounts.Returns(test);
        var controller = new AccountsController(context);
        var result = await controller.Index();
    }

有人可以帮我解决这个问题并指出我正确的方向吗?我已经阅读了博客和一本书,但仍然无法理解我应该在这里做什么?结果是一个ActionResult的任务,所以我断言是什么?我已经了解到你断言模拟并使用存根来满足依赖关系。那么我该怎么办?我读过的单元测试是要走的路,我不想放弃,所以我该怎么做?请帮帮忙?!

1 个答案:

答案 0 :(得分:1)

我认为你可能看到的东西可能过于复杂了。我认为测试的想法是将所有内容分解为最简单的形式(单位)。所以我可能会以编程方式创建Account,Bank等实例以进行测试。这样做的原因是为了测试你的逻辑在没有数据更改的情况下正在按照它所说的那样做,如果你使用数据库就会发生这种情况。

通过EF测试,我会检查是否从每个结果集中返回任何项目。

此外,我会测试您要执行的基本EF操作,即它是否返回所有银行?,是否返回所有帐户?,您可以创建银行吗?,您可以创建帐户等等。

我使用NUnit,但大多数单元测试框架都是类似的。

实际上,您正在检查是否通过了它,您需要定义使测试通过或失败的原因。

这可能就像这样简单:

Assert.IsTrue(result.Equals("Hello World"));

在测试表单时,与此集成的Selenium也非常有用。

希望有所帮助。

相关问题