asp.net-mvc如何测试的方法创建 DBContext 的位置?

发布时间: 2017/3/25 18:03:17
注意事项: 本文中文内容可能为机器翻译,如要查看英文原文请点击上面连接.

我没有很多的经验与单元测试。例如我有简单的方法在应用程序中︰

public void GetName()
    {
        UserRights rights = new UserRights(new DatabaseContext());
        string test = rights.LookupNameByID("12345");
        Console.WriteLine(test);
    }

在这种情况下我能够测试通过戏弄的 DatabaseContext,UserRights 类的所有方法,但是如何可以都测试 GetName() 方法吗?最佳做法是什么?应创建 DatabaseContext 的位置吗?

解决方法 1:

如果你想要测试 GetName 中正确孤立的方式 (即单元测试),那么你的方法不能使用 new 创建 UserRights 实例中的方法本身; 因为一个测试是真的只是另一个客户端的代码,因此它不能 (也不应该) 知道任何关于如何 GetName 内部工作原理

所以这就意味着,适当的单元测试,你必须能够与那些客户端完全控制-在案例中,在单元测试中的代码替换方法的所有依赖项是客户端。

在您发布的代码中,客户端代码已不能控制在所有超过 UserRights 也不 DatabaseContext ,所以这是必须改变的第一件事。

您需要修改您的代码以便 UserRights 可以由客户端提供实现。事实上,一旦这样做了,在哪里的问题 DatabaseContext 来从实际上是无为的单元测试,因为它并不关心如何 UserRights 本身执行其任务 !

当地有很多方式的这样做;您可以使用模拟或存根 (stub),您可以使用构造函数或方法的注射,你可以使用 UserRights 工厂。下面是一个示例的使用非常简单的存根,恕我直言是最好的开始,而且避免学会嘲弄框架 — — 我个人会为此使用 Mock,但那是因为我很懒:)

(下面的代码假定包含 GetName 的类被称为"UserService",并使用 xUnit 框架; 但 MSTest 会在只是正常工作)

让我们假设你有控制权的代码 UserService ,您可以 LookupNameByID 虚拟方法 (如果你不能那么你可能要走的路线,如果接口和嘲弄)

public class UserRights
{
    public virtual LookupNameByID(string id)
    {
        //does whatever a UserRights does.
    }
}

public class UserService
{
    readonly UserRights _rights;
    public UserService(UserRights rights)
    {
       _rights=rights; //null guard omitted for brevity
    }

    public string GetName(string id)
    {
       return _rights.LookupNameByID(id);
    }
}

现在在您的单元测试代码假设您创建一个子类的 UserRights 像这样︰

public class ExplodingUserRights: UserRights
{
     public override string LookupNameByID(string id)
     {
         throw new Exception("BOOM!");
     }
}

现在你可以编写一个测试,看看如何 GetName 坏的事发生时的反应︰

[Fact]
public void LookupNameByID_WhenUserRightsThrowsException_DoesNotReThrow()
{
   //this test will fail if an exception is thrown, thus proving that GetName doesn't handle exceptions correctly.
   var sut = new UserService(new ExplodingUserRights()); <-Look, no DatabaseContext!
   sut.GetName("12345");
}

和一个很好的事情发生时︰

public class HappyUserRights: UserRights
{
     public override string LookupNameByID(string id)
     {
         return "yay!";
     }
}

[Fact]
public void LookupNameByID_ReturnsResultOfUserRightsCall()
{
   //this test will fail if an exception is thrown, thus proving that GetName doesn't handle exceptions correctly.
   var sut = new UserService(new HappyUserRights()); 
   var actual = sut.GetName("12345");
   Assert.Equal("yay!",actual);
}

等等。请注意,我们永远不会去接近 DatabaseContext ,因为这是你只需要解决的问题当你单元测试 UserRights 类本身。(和在那一点上我将可能推荐使用吉荣的建议从他链接的文章,和做一个集成测试,除非安装程序为每个测试数据库的东西你不能或不会做,在这种情况下,您需要使用接口和模拟)

希望有帮助。

赞助商