代码之家  ›  专栏  ›  技术社区  ›  Extreme

如何在c语言中测试控制器方法#

  •  0
  • Extreme  · 技术社区  · 6 年前

    我最近开始对c代码进行单元测试,但以前从未测试过控制器类。我有下面的课程,我需要为此编写测试用例。

    namespace nH.MasterData.API.Controllers
    {
        [Produces("application/json")]
        [Route("api/AType")]
        public class ATypeController : Controller
        {
            private readonly IProcessor _domain;
            private readonly ILogger _logger;
            private const string Version = "VERSION_1";
            private const string Model = "model";
            private const string Entity = "AType";
    
            public ATypeController(IProxy proxy, ILogger<ATypeController> logger)
            {
                _logger = logger;
                var proxy = proxy.GetProxy();
                _domain = new InstitutionAddressProcessor(proxy);
            }
    
            [HttpGet]
            public OkObjectResult Get()
            {
                try
                {
                    return Ok(_domain.GetATypesMembers(Model, Version, Entity, MemberType.Leaf, null));
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex.Message + " " + ex.StackTrace);
                    return new OkObjectResult(BadRequest());
                }
            }
    
        }
    }
    

    在这里, _domain.GetATypesMembers() 不在我的项目中,我也不创建 _domain

    通常,我会 setup wcfMockService.Setup(x => x.GetATypesMembers(...).ReturnAsync(response); 但是我怎么能为这个写呢?

    我很感激你的建议。

    在构造函数中创建对象是一种糟糕的做法。但这是一个遗留代码,在许多地方都在使用。所以我只是试着在代码存在时编写测试。

    4 回复  |  直到 6 年前
        1
  •  2
  •   Nkosi    6 年前

    您亲身经历的是,为什么将类与实现问题紧密耦合是糟糕的设计。

    该控制器应该重构为依赖于抽象而不是具体化。

    namespace nH.MasterData.API.Controllers {
        [Produces("application/json")]
        [Route("api/AType")]
        public class ATypeController : Controller {
            private readonly IProcessor _domain;
            private readonly ILogger _logger;
            private const string Version = "VERSION_1";
            private const string Model = "model";
            private const string Entity = "AType";
    
            public ATypeController(IProcessor domain, ILogger<ATypeController> logger) {
                _logger = logger;            
                _domain = domain;
            }
    
            [HttpGet]
            public IActionResult Get() {
                try {
                    return Ok(_domain.GetATypesMembers(Model, Version, Entity, MemberType.Leaf, null));
                } catch (Exception ex) {
                    _logger.LogError(ex.Message + " " + ex.StackTrace);
                    return BadRequest();
                }
            }
        }
    }
    

    var processor = new Mock<IProcessor>();
    var logger = new Mock<ILogger<ATypeController>>();
    var controller = new ATypeController(processor.Object, logger.Object); 
    
    //...setup mocks
    

    从原始构造函数的外观来看 IProcessor

    这可以在合成根处得到满足。

    services.AddScoped<IProcessor>(_ => {                
        var proxy = _.GetService<IProxy>();
        return new InstitutionAddressProcessor(proxy.GetProxy());
    });
    
        2
  •  1
  •   Jonathon Chase    6 年前

    IProxy IProcessor 嘲笑。

    沿着这条线的一些东西应该可以让你在构建sut之后设置字段。

    // Arrange
    var sut = SutProvider.GetATypeController(); // A system under test factory.
    
    var mock = new Mock<IProcessor>();
    // ... mock setup ..
    
    typeof(ATypeController)
        .GetField("_domain", BindingFlags.Instance | BindingFlags.NonPublic)
        .SetValue(sut, mock.Object);
    
    // Act
    var result = sut.Get();
    
    // Assert
    // ... assertions of result
    

    理想的 但是在使用遗留代码时,有时必须做一些不干净的事情来设置测试对象的正确状态。我强烈建议您仅将这些内容放在测试中,并适当说明不要在“真实”代码中这样做。

    SutProvider是一个简单的工厂,实现可以如下所示:

    public class SutProvider 
    {
        public static ATypeController GetATypeController() => new ATypeController(GetProxy(), GetATypeControllerLogger());
    
        public static IProxy GetProxy() {
            // Either return a valid IProxy, or set up a mock that can return a result from the GetProxy method that is valid enough to withstand InstitutionAddressProcessor's constructor.
        }
    
        public static ILogger<ATypeController> GetATypeControllerLogger() => new Mock<ILogger<ATypeController>>().Object;
    }
    

    InstitutionAddressProcessor 的构造函数来找出传递足够有效代理的最佳方法。

        3
  •  0
  •   Gauravsa    6 年前

    我会用的 Dependency Injection 就是这个案子。它是一种 Inversion Control . 我将把它作为参数传递,而不是在方法中传递proxy和\u域(proxy正在传递,但我将把\u域作为参数传递)。\u域将在中的某个位置实例化 Main like method 或者你可以用 ['AutoFac'] . 然后就很容易创建单元测试了。

    下面是一个关于使用 Dependency Injection

    正如上面用户所指出的,有一个紧密的耦合使得单元测试变得困难。

        4
  •  0
  •   Jordan Brooklyn    6 年前

    你不能免费得到任何东西。如果你想测试逻辑,你必须把事情解耦。如果你不将它们解耦,你将无法正确地测试,因为你正在测试一个你自己无法测试的依赖性的东西。所以没有

    虽然它可能是遗留代码,但是像resharper这样一个像样的工具(我与之完全没有关系)可以帮助您进行重构。一旦注入服务,就可以进行适当的单元测试。