如何访问Moq模拟类的私有成员?为何PrivateObject获取失败?
Moq模拟类无法通过PrivateObject访问私有成员的原因
使用PrivateObject类可以访问普通类的私有成员,但无法访问经Moq模拟后的类的私有成员。如下示例代码中,测试模拟类Temp时,通过PrivateObject获取私有成员I会抛出System.MissingMethodException,请问该成员无法被找到的原因是什么?
using System.Reflection; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using Xunit; using Assert = Xunit.Assert; namespace MyNamespace; public class Temp { private int I { get; set; } public int PublicI { get => I; set => I = value; } public Temp(int i) { I = i; } } public class Testing { [Fact] [Trait("Category", "Unit")] public void TestNormal() { var temp = new Temp(7); Assert.Equal(7, temp.PublicI); temp.PublicI = 8; Assert.Equal(8, temp.PublicI); var po = new PrivateObject(temp); var publicI = po.GetFieldOrProperty("PublicI"); Assert.Equal(8, publicI); var privateI = po.GetFieldOrProperty("I", BindingFlags.NonPublic | BindingFlags.Instance); Assert.Equal(8, privateI); } [Fact] [Trait("Category", "Unit")] public void TestMocked() { var mock = new Mock<Temp>(7); Assert.Equal(7, mock.Object.PublicI); mock.Object.PublicI = 8; Assert.Equal(8, mock.Object.PublicI); var po = new PrivateObject(mock.Object); var publicI = po.GetFieldOrProperty("PublicI"); Assert.Equal(8, publicI); // Following line throws System.MissingMethodException var privateI = po.GetFieldOrProperty("I", BindingFlags.NonPublic | BindingFlags.Instance); Assert.Equal(8, privateI); } }
原因分析
- Moq生成动态代理子类:Moq创建模拟对象时,会动态生成一个继承自
Temp的子类。私有成员I属于父类的非公开成员,子类无法继承该成员,所以代理对象里根本不存在I。 - PrivateObject的查找逻辑限制:
PrivateObject是基于传入对象的实际类型(也就是Moq的代理子类)来查找成员的,它不会自动去父类中检索非公开成员,因此找不到I就会抛出异常。 - 公共成员的行为是模拟的:你看到
mock.Object.PublicI能正常读写,是因为Moq默认拦截了公共成员的调用,模拟出了对应的返回和赋值行为,但这并没有真正操作父类的私有成员I,底层的私有属性根本没被实际使用。
内容的提问来源于stack exchange,提问作者huha
相关产品推荐
相关产品推荐

