简体   繁体   English

如何使这个单元可测试

[英]How to make this Unit Testable

Below I have some code that that I cannot Unit test because it tries to read settings from IIS7 and unfortunately our nightly build machine does not have IIS7. 下面我有一些代码,我不能单元测试,因为它试图从IIS7读取设置,不幸的是我们的夜间构建机器没有IIS7。 The only thing I can think of is to pass the ServerManager into the method, but then again in the caller I will have a ServerManager that will make that method unable to be unit tested. 我唯一能想到的是将ServerManager传递给方法,但是再次在调用者中我会有一个ServerManager,它将使该方法无法进行单元测试。 We use MOQ for our Mock library. 我们使用MOQ作为我们的Mock库。

        public ISection GetCurrentSettings(string location, Action<string> status)
    {
        #region Sanity Checks

        if (string.IsNullOrEmpty(location))
        {
            throw new ArgumentNullException("location");
        }
        if (status == null)
        {
            throw new ArgumentNullException("status");
        }
        #endregion

        ISection section = null;

        _logger.Debug(string.Format("Retrieving current IIS settings for app at {0}.", location));
        status("Getting current IIS settings.");
        using (ServerManager manager = new ServerManager())
        {
            var data = (from site in manager.Sites
                        from app in site.Applications
                        from vdir in app.VirtualDirectories
                        where vdir.PhysicalPath.Equals(location, StringComparison.CurrentCultureIgnoreCase)
                        select new {Website = site, App = app}).SingleOrDefault();

            if (data == null)
            {
                _logger.Debug(string.Format("Could not find an application at {0} in IIS. Going to load the defaults instead.", location));
                //ToDo possibly load defaults
            }
            else
            {
               _logger.Debug(string.Format("Application found in IIS with website: {0} and a path of {1}", data.Website.Name, data.App.Path));
                int port =
                    data.Website.Bindings.Where(b => b.EndPoint != null).Select(b => b.EndPoint.Port).Single();


                section = new IISSection
                    {
                        ApplicationPoolName = data.App.ApplicationPoolName,
                        VirtualDirectoryAlias = data.App.Path,
                        WebsiteName = data.Website.Name,
                        WebsiteRoot = data.App.VirtualDirectories[0].PhysicalPath,
                        Port = port.ToString(CultureInfo.InvariantCulture),
                        WillApply = true,
                        AnonymousUser = _userService.GetUserByType(UserType.Anonymous)
                    };
            }

            return section;

        }

Without rewriting your code fully, the general idea would be to pass in an ISettingReader* (implemented as IisSettingReader), which would expose methods that would get the data you need from IIS. 如果不完全重写代码,一般的想法是传入一个ISettingReader *(实现为IisSettingReader),它将公开可以从IIS获取所需数据的方法。 Then, you can stub in the ISettingReader to return what you need, by passing ISettingReader into the method/class 然后,您可以通过将ISettingReader传递给方法/类,在ISettingReader中存根以返回所需内容

*Or, IServerManager as it seems to be the current name, but I am not sure if that is IIS specific *或者,IServerManager似乎是当前的名称,但我不确定这是否是IIS特定的

UPDATE UPDATE

To be more specific, as Darin Dimitrov elaborated, you need to pull all of the dependencies outside of the method and pass them in via parameter/constructor/property injection. 更具体地说,正如Darin Dimitrov所阐述的那样,您需要将所有依赖项拉出方法之外,并通过参数/构造函数/属性注入传递它们。 This will require a rewrite of the code as it stands in its current state. 这将需要重写代码,因为它处于当前状态。

If not (and I do suggest a rewrite), then you can use something like TypeMock, which supposedly can fake the dependencies INSIDE a class, but I have not used this myself and only know what I have read on it. 如果不是(我建议重写),那么你可以使用类似TypeMock的东西,据说它可以伪造一个类中的依赖项,但我自己并没有使用它,只知道我已经阅读过它。

Use Moq . 使用Moq

This will allow you to create a mocked version of ISettings rather than having to create a real one. 这将允许您创建一个模拟的ISettings版本,而不是创建一个真实的版本。 It has the added advantage of allowing you to specify your own functionality as well. 它还具有允许您指定自己的功能的附加优势。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM