Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/290.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# 依赖注入的单元测试_C#_Unit Testing_Dependency Injection_Inversion Of Control - Fatal编程技术网

C# 依赖注入的单元测试

C# 依赖注入的单元测试,c#,unit-testing,dependency-injection,inversion-of-control,C#,Unit Testing,Dependency Injection,Inversion Of Control,我正在为国际奥委会使用Autofac 这是我的容器启动器类,其职责是注册依赖项 public class ContainerInit { public static IContainer BuildContainer() { var conFac = new ContainerFactory(); var builder = new ContainerBuilder(); builder.Regi

我正在为国际奥委会使用
Autofac

这是我的容器启动器类,其职责是注册依赖项

 public class ContainerInit
 {
      public static IContainer BuildContainer()
      {
            var conFac = new ContainerFactory();
            var builder = new ContainerBuilder();
            builder.Register(conFac).As<IContainerFactory>().SingleInstance();
            builder.Register(c=> new MainClass(conFac)).As<IMainClass>().SingleInstance();
            builder.Register(c=> new Database(conFac)).As<IDatabase>().SingleInstance();
             var logger = LoggUtil.CreateLogger();
            builder.Register(logger).As<ILogger>().SingleInstance();

            var container = builder.Build();
            ContainerFactory.SetContainer(container);
            return container;
      }
 }
所以很难对这些类进行单元测试


如何才能想出一个好的解决方案?

在这里,我想与大家分享我在项目中使用的解决方案

为了对特定功能进行单元测试,我使用以下结构

[TestClass]
public class TestSomeFunction
{
    public IComponentContext ComponentContext { get; set; }       

    [TestInitialize]
    public void Initialize()
    {
       //Registering all dependencies required for unit testing
       this.ComponentContext = builder.Build(); //You have not build your container in your question
    }

    [TestMethod]
    public void Testfunction()
    {
       //Resolve perticular dependency
       var _logger = containerFactory.Resolve<ILogger>();   
       //Test my function
       //use _logger 
    }
}
[TestClass]
公共类TestSomeFunction
{
公共IComponentContext组件上下文{get;set;}
[测试初始化]
公共无效初始化()
{
//注册单元测试所需的所有依赖项
this.ComponentContext=builder.Build();//您尚未在问题中构建容器
}
[测试方法]
公共void Testfunction()
{
//解决相关依赖
var_logger=containerFactory.Resolve();
//测试我的功能
//使用记录器
}
}

更好的方法是将类中所需的依赖项传递给构造函数:

public class MainClass : IMainClass
{       
    private readonly ILogger _logger;
    private readonly IDatabase _db;

    public MainClass(ILogger logger, IDatabase db)
    {
        _logger = logger;  
        _db = db;
    }

    public void AddDetails(Data data)
    {
        //do some business operations 
        _db.Add(data);
        _logger.Information("added");
    }
}
然后,您可以使用模拟框架,例如模拟类依赖项,并对是否调用了依赖项执行验证:

[TestClass]
public class UnitTest1
{
    private Mock<ILogger> _mockLogger = new Mock<ILogger>();
    private Mock<IDatabase> _mockDb = new Mock<IDatabase>();

    [TestMethod]
    public void TestMethod1()
    {
        // arrange
        var mainClass = new MainClass(_mockLogger.Object, _mockDb.Object);
        var data = new Data();

        // act
        mainClass.AddDetails(data);

        // assert    
        _mockDb
            .Verify(v => v.Add(data), Times.Once);
    }
}
[TestClass]
公共类UnitTest1
{
私有Mock_mockLogger=new Mock();
私有Mock_mockDb=new Mock();
[测试方法]
公共void TestMethod1()
{
//安排
var mainClass=新的mainClass(_mockLogger.Object,_mockDb.Object);
var data=新数据();
//表演
mainClass.AddDetails(数据);
//断言
_mockDb
.验证(v=>v.Add(数据),次.次);
}
}

但我不会验证您的日志消息,因为这可能会更改并使测试变得脆弱。只验证对实现方法的目的至关重要的功能。

当前的服务定位器反模式会使代码难以单独测试,并使类对其实际依赖的内容产生误导

MainClass
应该进行重构,以遵循

对于依赖于容器工厂的任何其他类,如
数据库
,也应该遵循相同的模式

但是,您还需要相应地重构容器注册

public class ContainerInit {
    public static IContainer BuildContainer() {
        var builder = new ContainerBuilder();
        builder.RegisterType<MainClass>().As<IMainClass>().SingleInstance();
        builder.RegisterType<Database>().As<IDatabase>().SingleInstance();
        var logger = LoggUtil.CreateLogger();
        builder.Register(logger).As<ILogger>().SingleInstance();

        var container = builder.Build();
        return container;
    }
}

您要测试的是什么,一个特定的函数??当你测试一个函数时,IoC真的很有帮助。如果您正在针对特定函数进行单元测试,那么在
[TestInitialize]
中注册依赖项,并在
[TestMethod]
中解决它您的
IContainerFactory
是一个反模式,称为服务定位器。不要将此
IContainerFactory
注入构造函数,而是直接注入所有必需的依赖项。@kudlatiger,它能回答您的问题吗?谢谢您的快速回复。问题是如何在“MainClass”中测试方法?更新了“构建”问题是的,这是一个更干净、更可靠的方法
public class MainClass : IMainClass  
    private readonly ILogger logger;
    private readonly IDatabase db;

    public MainClass(ILogger logger, IDatabase db) {
        this.logger = logger;  
        this.db = db;
    }

    public void AddDetails(Data data) {
        //do some business operations 
        db.Add(data);
        logger.Information("added");
    }
}
public class ContainerInit {
    public static IContainer BuildContainer() {
        var builder = new ContainerBuilder();
        builder.RegisterType<MainClass>().As<IMainClass>().SingleInstance();
        builder.RegisterType<Database>().As<IDatabase>().SingleInstance();
        var logger = LoggUtil.CreateLogger();
        builder.Register(logger).As<ILogger>().SingleInstance();

        var container = builder.Build();
        return container;
    }
}
[TestClass]
public class MainClassTests {    
    [TestMethod]
    public void Should_AddDetails_To_Database() {
        // Arrange
        var mockDb = new Mock<IDatabase>();
        var data = new Data();
        var mainClass = new MainClass(Mock.Of<ILogger>(), mockDb.Object);

        // Act
        mainClass.AddDetails(data);

        // Assert    
        mockDb.Verify(_ => _.Add(data), Times.Once);
    }
}