C# 使用内部 属性 Setter 模拟 Class
C# Mock a Class With an Internal Property Setter
我正在尝试构建单元测试。
class 位置在 第三方库 中实现。但是对于我的单元测试,我需要将大小 属性 设置为特定值。
public class Position
{
private double _size;
private double Size
{
get
{
return _size;
}
internal set
{
_size = value;
}
}
}
我读了这个post:How do you create a unit-testing stub for an interface containing a read-only member?
但不知道如何让它为我工作。
这是正在测试的class(只是一个简化的例子)。 CalcPositionMetric()
方法中的 pos
参数必须是 Position
类型:
public class PositionMetrics
{
public PositionMetrics()
{}
public double CalcPositionMetric(Position pos)
{
return 2 * pos.Size;
}
}
这是我的单元测试的一部分:
using NUnit.Framework;
using NMock;
[TestFixture]
public class PositionUnitTests
{
[Test]
public void TestPosition()
{
Mock<Position> tmpPosMock = mFactory.CreateMock<Position>();
tmpPosMock.Expects.One.GetProperty(v => v.Size).WillReturn(7); /* !!! Exception !!! System.ArgumentException : mock object position has a getter for property Size, but it is not virtual or abstract */
/* Execute Test with tmpPositions*/
PositionMetrics pm = new PositionMetrics();
double result = pm.CalcPositionMetric(tmpPosMock.MockObject)
Assert.AreEqual(14, result);
}
}
但是如您所见,我得到了一个例外。有人可以帮我解决这个问题吗?也欢迎任何其他解决方案!
干杯
康斯坦丁
更新问题的新答案我建议您为此引入某种代理接口。请看下面的代码:
interface IPosition {
int Size { get; }
}
class Position { //in 3rd party lib
public int Size {
get { return 5; }
}
}
class RealPosition : IPosition { //use this as your real object instead of using Position directly
private Position position;
public RealPosition(Position position) {
this.position = position;
}
public int Size {
get { return position.Size; }
}
}
class MockPosition : IPosition { //use this for testing
public int Size{ get; set; }
}
public class Program {
static void Main(string[] args) {
var pos = new MockPosition { Size = 7 };
Console.WriteLine(Calc(pos)); //prints 14
Console.ReadLine();
}
static int Calc(IPosition pos) { //change your method signature to work with interface
return pos.Size * 2;
}
}
旧答案 如果 class 不是 sealed
你不需要任何模拟库。只需对所需的属性使用 new
修饰符,如下所示:
class Position {
public int Size { get { return 5; } }
}
class MockPosition : Position {
public new int Size { get; set; }
}
....
var mock= new MockPosition();
mock.Size = 7;
要在某种列表中使用这些项目,您必须像这样转换它们:
var items = new List<Position>();
for (int i = 0; i < 5; i++) {
items.Add(new MockPosition { Size = i });
}
foreach (var item in items.Cast<MockPosition>()) {
Console.Write("{0}\t", item.Size); //prints 0 1 2 3 4
}
如果它是密封的并且 属性 不是虚拟的那么你将不得不使用一些其他技术,Moq
(我猜你正在使用)不允许
我正在尝试构建单元测试。 class 位置在 第三方库 中实现。但是对于我的单元测试,我需要将大小 属性 设置为特定值。
public class Position
{
private double _size;
private double Size
{
get
{
return _size;
}
internal set
{
_size = value;
}
}
}
我读了这个post:How do you create a unit-testing stub for an interface containing a read-only member? 但不知道如何让它为我工作。
这是正在测试的class(只是一个简化的例子)。 CalcPositionMetric()
方法中的 pos
参数必须是 Position
类型:
public class PositionMetrics
{
public PositionMetrics()
{}
public double CalcPositionMetric(Position pos)
{
return 2 * pos.Size;
}
}
这是我的单元测试的一部分:
using NUnit.Framework;
using NMock;
[TestFixture]
public class PositionUnitTests
{
[Test]
public void TestPosition()
{
Mock<Position> tmpPosMock = mFactory.CreateMock<Position>();
tmpPosMock.Expects.One.GetProperty(v => v.Size).WillReturn(7); /* !!! Exception !!! System.ArgumentException : mock object position has a getter for property Size, but it is not virtual or abstract */
/* Execute Test with tmpPositions*/
PositionMetrics pm = new PositionMetrics();
double result = pm.CalcPositionMetric(tmpPosMock.MockObject)
Assert.AreEqual(14, result);
}
}
但是如您所见,我得到了一个例外。有人可以帮我解决这个问题吗?也欢迎任何其他解决方案!
干杯 康斯坦丁
更新问题的新答案我建议您为此引入某种代理接口。请看下面的代码:
interface IPosition {
int Size { get; }
}
class Position { //in 3rd party lib
public int Size {
get { return 5; }
}
}
class RealPosition : IPosition { //use this as your real object instead of using Position directly
private Position position;
public RealPosition(Position position) {
this.position = position;
}
public int Size {
get { return position.Size; }
}
}
class MockPosition : IPosition { //use this for testing
public int Size{ get; set; }
}
public class Program {
static void Main(string[] args) {
var pos = new MockPosition { Size = 7 };
Console.WriteLine(Calc(pos)); //prints 14
Console.ReadLine();
}
static int Calc(IPosition pos) { //change your method signature to work with interface
return pos.Size * 2;
}
}
旧答案 如果 class 不是 sealed
你不需要任何模拟库。只需对所需的属性使用 new
修饰符,如下所示:
class Position {
public int Size { get { return 5; } }
}
class MockPosition : Position {
public new int Size { get; set; }
}
....
var mock= new MockPosition();
mock.Size = 7;
要在某种列表中使用这些项目,您必须像这样转换它们:
var items = new List<Position>();
for (int i = 0; i < 5; i++) {
items.Add(new MockPosition { Size = i });
}
foreach (var item in items.Cast<MockPosition>()) {
Console.Write("{0}\t", item.Size); //prints 0 1 2 3 4
}
如果它是密封的并且 属性 不是虚拟的那么你将不得不使用一些其他技术,Moq
(我猜你正在使用)不允许