Используя класс PrivateObject, я могу получить доступ к частным членам класса.
Но я не могу получить доступ к частным членам, если этот класс высмеивается с помощью Moq.
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);
}
}
В строке после комментария стоит MissingMethodException. Почему он не находит мой член?
Зачем вам пытаться протестировать макет объекта?
PrivateObject по сути работает так же, как и использование чистого отражения. Однако я согласен с приведенными выше комментариями: зачем вам это нужно? Похоже, вы хотите протестировать свой Сут и поиздеваться над некоторыми его частями. В любом случае тестирование частных членов редко бывает хорошей идеей, и его следует проводить только между рефакторингами или чем-то подобным.
Unittest должен проверять модуль и поведение этого модуля (поведенческий контракт классов). То, что вы тестируете, — это деталь реализации, поэтому вы, вероятно, нарушаете тест при изменении кода. Это противоположно тому, чего вы хотите, по крайней мере, в разработке через тестирование. Тем не менее, мы не видим определения PrivateObject, а только определения Temp. Может быть, в PrivateObject его просто нет?
@Ralf PrivateObject происходит из Microsoft.VisualStudio.TestTools.UnitTesting:.





Mock не издевается над private участниками (не вмешивается в личные дела высмеиваемого класса), например. урок морской свинки
public class MyClass
{
public int MyMethod() => MyPrivateMethod() * 1000;
private int MyPrivateMethod() => 123;
}
И чистый инспектор отражений
private static void PrivateMethods(object value) {
var methodNames = value
.GetType()
.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic)
.Select(item => item.Name);
Console.WriteLine(string.Join(Environment.NewLine, methodNames));
}
Мы легко можем увидеть разницу:
// Original class
PrivateMethods(new MyClass());
Console.WriteLine();
// Mocked class
Mock<MyClass> mock = new Mock<MyClass>();
PrivateMethods(mock.Object);
Выход:
MyPrivateMethod
MemberwiseClone
Finalize
MemberwiseClone
Finalize
Обратите внимание, что mock.Object не является MyClass:
// False
Console.WriteLine(mock.Object.GetType() == typeof(MyClass));
// Castle.Proxies.MyClassProxy
Console.WriteLine(mock.Object.GetType().FullName);
Наконец, если вы хотите, чтобы метод высмеивали, делайте что угодно, кроме private (internal, protected, protected internal, private protected)
Что вы пытаетесь проверить и почему? Для меня это не имеет смысла.