延续前篇【C#】小知识 #8 : 使用partial class + private内部类别,避免日后专案开发受限程度
笔者以单元测试做开发,发现使用非public内部类别
虽然可以减低日后维护限制,但是没办法直接做单元测试
,因为可见度问题。
虽然单元测试的意义以及封装的用意"用户原本就不需要了解,非public的行为"
,基本上我们不太希望把不该开放的类别或成员给外部的组件存取,但为了测试专案,不开放存取权限又很难做事,想要解决这问题:
举例: 现在有一个类别里面再包覆私有内部工具类别,想要做单元测试
public class MyClass{private class NestedClass{private static string CommonConcat(params string[] paras){return $"{para1},{para2}";}}}
【一般作法1】internal + AssemblyInfo.cs 添加 [assembly: InternalsVisibleTo("单元测试专案名称")]
逻辑:
在专案添加AssemblyInfo.cs
cs档内容添加[assembly:System.Runtime.CompilerServices.InternalsVisibleTo(测试专案名称)]
将内部类别改为internal
结果就可以看到单元测试能取得访问权限,如图片
【一般作法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); } }}
【反面教材】反射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老师的测试概念连结 : 连结请点击 , 推荐读者阅读。