Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/263.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# TDD-想用一个假的存储库来测试我的服务层,但是怎么做呢?_C#_Asp.net_Asp.net Mvc_Repository Pattern - Fatal编程技术网

C# TDD-想用一个假的存储库来测试我的服务层,但是怎么做呢?

C# TDD-想用一个假的存储库来测试我的服务层,但是怎么做呢?,c#,asp.net,asp.net-mvc,repository-pattern,C#,Asp.net,Asp.net Mvc,Repository Pattern,我设计了一个使用存储库模式的应用程序,然后设计了一个单独的服务层,如下所示: public class RegistrationService: IRegistrationService { public void Register(User user) { IRepository<User> userRepository = new UserRepository(); // add user, etc } } 公共类注册服

我设计了一个使用存储库模式的应用程序,然后设计了一个单独的服务层,如下所示:

public class RegistrationService: IRegistrationService
{
    public void Register(User user)
    {
        IRepository<User> userRepository = new UserRepository();
        // add user, etc
    }
}
公共类注册服务:IRegistrationService
{
公共无效登记簿(用户)
{
IRepository userRepository=新的userRepository();
//添加用户等
}
}

如您所见,我正在Register方法中实例化我的存储库。现在,当我想编写一些单元测试时,我真的无法使用一个假的存储库来替换它,可以吗

不过,我不想将存储库添加为类变量(并通过构造函数进行设置),因为我认为这会让我的代码“难闻”(并非所有方法都需要所有存储库,我也不需要调用层了解存储库等)


建议?

您可以使用一个IOC容器,然后注册一个不同的存储库。

依赖项注入对于这类事情非常有用:

public class RegistrationService: IRegistrationService
{
    public void Register(User user)
    {
        this(user, new UserRepository());
    }

    public void Register(User user, IRepository<User> userRepository)
    {
        // add user, etc
    }

}
公共类注册服务:IRegistrationService
{
公共无效登记簿(用户)
{
此(用户,新用户存储库());
}
公共无效注册表(用户、IRepository用户存储库)
{
//添加用户等
}
}
通过这种方式,您可以使用UserRepository作为默认存储库,并为您需要的其他内容传入自定义(模拟或测试存根)IRepository。如果您不想将第二个register方法的作用域全部公开,您可能还需要更改它的作用域

一个更好的替代方案是使用一个IoC容器,它将为您购买比上述示例更解耦的语法。你可以得到这样的结果:

public class RegistrationService: IRegistrationService
{
    public void Register(User user)
    {
        this(user, IoC.Resolve<IRepository<User>>());
    }

    public void Register(User user, IRepository<User> userRepository)
    {
        // add user, etc
    }

}
公共类注册服务:IRegistrationService
{
公共无效登记簿(用户)
{
此(用户,IoC.Resolve());
}
公共无效注册表(用户、IRepository用户存储库)
{
//添加用户等
}
}

有很多IoC容器,正如其他人的答案所列出的,或者您也可以。

我的建议仍然是将存储库移动到类参数,并在需要时使用IoC容器注入存储库。这样,代码简单且可测试。

您应该使用控制反转或依赖项注入

您的类不应该绑定到另一个类的实现,特别是跨这样的层,而应该将表示用户存储库的接口作为构造函数或属性。然后,当它运行时,您提供了具体的实现并使用它。然后,您可以构建实现存储库接口并在测试时提供的赝品

国际奥委会有很多容器,Unity、Ninject、Castle Windsor和StructureMap等等


我只是想澄清一下,在单元测试期间,我不知道您是否希望实际使用IOC容器。当然,集成测试,但是对于单元测试,只需重新创建您正在测试的对象,并在该过程中提供您的伪代码。至少在IMO,IOC容器在应用程序或集成测试级别提供帮助,并使配置更容易


您的单元测试可能应该保持“纯粹”,只处理您试图测试的对象。至少这对我来说是有效的。

你需要使用依赖注入。UserRepository是RegistrationService类的依赖项。为了使类能够正确地进行单元测试(即与它们的依赖项隔离),您需要“反转”控制依赖项创建的内容。目前,您拥有直接控制权,并且正在内部创建它们。只需反转该控件,并允许外部(如Castle Windsor之类的IoC容器)注入它们:

public class RegistrationService: IRegistrationService
{
    public RegistrationService(IRepository<User> userRepo)
    {
        m_userRepo = userRepo;
    }

    private IRepository<User> m_userRepo;

    public void Register(User user)
    {
        // add user, etc with m_userRepo
    }
}
公共类注册服务:IRegistrationService
{
公共注册服务(IRepository userRepo)
{
m_userRepo=userRepo;
}
私人IRepository m_userRepo;
公共无效登记簿(用户)
{
//使用m_userRepo添加用户等
}
}

我想我忘记加了。一旦你允许你的依赖项被注入,你就打开了它们被模仿的可能性。由于您的RegistrationService现在将其依赖用户存储库作为其构造函数的输入,因此您可以创建一个模拟存储库并将其传入,而不是一个实际的存储库。

只是为了让每个人都说得更清楚一点(或者可能不是),IOC的基本工作方式是你告诉它用Y代替X。所以你要做的是接受IRepository(正如其他人所说)作为参数,然后在IOC内部,你会告诉它用MockedRepository(例如)代替IRepository,用于特定的类

如果您使用允许web.config初始化的IoC,则可以使从dev到prod的转换非常顺利。您只需在配置文件中修改适当的参数,就可以开始了—无需触摸代码。稍后,如果您决定移动到另一个数据源,您只需将其切换出去,就可以开始了

国际奥委会是一些有趣的爱的东西


另一方面,如果您只想进行单元测试,那么您也可以在没有IOC注入的情况下进行测试。您可以通过重载构造函数来接受IRepository,然后通过这种方式传递模拟的repo来实现这一点。

我正在做一些事情,嗯,目前几乎是一字不差地进行。我正在使用MOQ模拟我的IUserDataRepository的代理实例

从测试的角度来看:

//arrange
var mockrepository = new Mock<IUserDataRepository>();
// InsertUser method takes a MembershipUser and a string Role
mockrepository.Setup( repos => repos.InsertUser( It.IsAny<MembershipUser>(), It.IsAny<string>() ) ).AtMostOnce();

//act
var service = new UserService( mockrepository.Object );
var createResult = service.CreateUser( new MembershipUser(), "WebUser" );

//assert
Assert.AreEqual( MembershipCreateUserResult.Success, createResult );
mockrepository.VerifyAll();
//排列
var mockrepository=new Mock();
//InsertUser方法接受MembershipUser和string角色
mockrepository.Setup(repos=>repos.InsertUser(It.IsAny(),It.IsAny()).AtMostOnce();
//表演
var service=newuserservice(mockrepository.Object);
var createResult=service.CreateUser(新成员身份用户(),“WebUser”)