【C#】小知识 #9 : 解决私有内部类别单元测试问题:使用 internal + AssemblyInfo.cs 与

延续前篇【C#】小知识 #8 : 使用partial class + private内部类别,避免日后专案开发受限程度

笔者以单元测试做开发,发现使用非public内部类别虽然可以减低日后维护限制,但是没办法直接做单元测试,因为可见度问题。

20190129152804-image.png

虽然单元测试的意义以及封装的用意"用户原本就不需要了解,非public的行为",基本上我们不太希望把不该开放的类别或成员给外部的组件存取,但为了测试专案,不开放存取权限又很难做事,想要解决这问题:

John Wu大大的文章 internal + 修改 AssemblyInfo.cs 方式 (建议作法)改为 protected + 继承 (视情况)可以使用反射System.Reflection.MethodBase.Invoke。 (不建议,负面教材)

举例: 现在有一个类别里面再包覆私有内部工具类别,想要做单元测试

public class MyClass{private class NestedClass{private static string CommonConcat(params string[] paras){return $"{para1},{para2}";}}}

【一般作法1】internal + AssemblyInfo.cs 添加 [assembly: InternalsVisibleTo("单元测试专案名称")]

逻辑:

在专案添加AssemblyInfo.cscs档内容添加[assembly:System.Runtime.CompilerServices.InternalsVisibleTo(测试专案名称)]将内部类别改为internal

结果就可以看到单元测试能取得访问权限,如图片
20190129214843-image.png

【一般作法2】改为protected权限

逻辑:放宽准许protected使继承类别可以使用,如以下代码
注意:不能测试实体类别,因为不能继承。

namespace UnitTestProject{    public class MyClass    {        protected class NestedClass        {            public static string CommondConcat(params string[] paras)            {                return string.Join(",", paras);            }        }    }    [TestClass]    public class TestClass : MyClass    {        [TestMethod]        public void CommondConcatTest()        {            var excepted = "Hello,ITHelp";            var result = MyClass.NestedClass.CommondConcat("Hello", "ITHelp");            Assert.AreEqual(excepted, result);        }    }}

20190129170553-image.png

【反面教材】反射Invoke直接呼叫私有方法

原先我是使用此方式,藉此直接呼叫非公开的内部类别,但是经过91老师指点才知道错得离谱。
这违反测试的核心意义:『应该以使用实际情境去考量』,使用者正常不会使用反射来呼叫该方式,这样只会造成误导、可读性差。

另外如以下Code,可以发现呼叫方式是使用弱维护字串,所以方法改名或是删除无法在编译前检查,这样会造成后续维护困扰。

public static class NestedTypeHelper{public static object CallStaticNestedTypeMethod(System.Type type, string nestedClassName, string methodName, object[] parameters = null){var nestedType = type.GetTypeInfo().DeclaredNestedTypes.SingleOrDefault(w => w.Name == nestedClassName);var methodInfo = nestedType.DeclaredMethods.SingleOrDefault(w => w.Name == methodName);return methodInfo.Invoke(null, parameters);}}
var result = CallStaticNestedTypeMethod(type: typeof(MyStaticObject), nestedClassName: "MyClass",methodName: "CommonConcat", parameters: new[] { "Hello","ITHelp" });Console.WriteLine(result); //结果:Hello,ITHelp

最后补上91老师的测试概念连结 : 连结请点击 , 推荐读者阅读。


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章