我已经获得了一些具有这种通用结构的代码:
public class A
{
int Foo { get; set; }
byte Bar { get; set; }
}
public class B
{
A[] _Baz = new A[10];
A[] Baz
{
get { return _Baz; }
set { _Baz = value; }
}
}
我知道,我知道暴露一个阵列,不是很好,但它是我给予的工作。
无论如何,我希望模拟B类并将一些数组元素设置为消费代码使用的特定值。
似乎moq不能直接执行此操作,但我已经看到了模拟A类数组并通过B类模拟返回的建议。有点像:
var mockAArray = new Mock<A>[10];
mockAArray[3] = new Mock<B>();
var mockB = new Mock<B>();
mockB.Setup(x => x.A).Returns(mockAArray);
我说的有点因为实际上没有用,我知道我应该尝试返回类似mockAArray.Object
的内容,但我无法找到正确的语法来实现这一点。< / p>
编辑: 使用dee提供的答案,上面例子的正确语法是:
IA[] tmpAArray = new A[10];
var mockA = new Mock<IA>;
mockA.Setup(x => x.Foo).Returns(1234);
tmpAArray[3] = mockA.Object;
var mockB = new Mock<IB>;
mockB.Setup(y => y.Baz).Returns(tmpAArray);
结束编辑
最终,我想重构代码以摆脱暴露的数组,但我也希望能够通过这个测试来帮助捕获任何破坏
编辑: 好的,我被问到一个更复杂的情况,我想考虑这样做。所以这里的另一个稍微复杂一点,请记住不是真的,例如。
public class MySerialPort : ISerialPort
{
SerialPort _port;
... // properties exposing _port properties
MySerialPort()
{
_port = new SerialPort;
}
void Open()
{
_port.Open();
}
void Close()
{
_port.Close();
}
... // more methods
}
public class PortManager
{
ISerialPort[] ports = new MySerialPort[10];
ISerialPort[] Port
{
get { return ports; }
set { ports = value; }
}
... // properties for managing the ports
... // some methods for good measure
}
public class TestClass()
{
int SomeMagicRoutine(PortManager manager)
{
// Some routine that takes the values in manager
// and the values in ports and returns an answer.
}
}
只是启动一个真实的MySerialPort和管理器实例数组会使测试变得困难,想象一下如果是一个Streams数组而不是很好。这就是为什么我更喜欢嘲笑。显然,对于最简单的情况,只使用真实实例就可以了,不幸的是,现实世界并不总是允许我们采取简单的选择。
无论如何,最初的简单例子是试图简洁。
答案 0 :(得分:1)
这取决于您在B
中使用课程Class Under Test (CUT)
的方式。如果您有可能如何将类B
的实例注入CUT,那么您不需要模拟。
例如,使用构造函数注入,你会有类似的东西。
public class CUT
{
private B _b;
public CUT(B b)
{
_b = b;
}
}
[TestMethod]
public void test01()
{
// Arrange
// here you create your fake-array
A[] bazFake = new A[] { new A { Foo = 1, Bar = 2 } };
B bFake = new B();
bFake.Baz = bazFake;
// and inject this fake-object into the CUT
CUT cut = new CUT(bFake);
// Act
// ...
// Assert
// ...
}
编辑:
然后,使用Moq
的最简单方法是创建IPortManager
界面:
public interface IPortManager
{
ISerialPort[] Port { get; set; }
// properties for managing the ports
// some methods for good measure
}
然后班级PortManager
将实施它:
public class PortManager : IPortManager
{ ... }
然后在测试中模拟IPortManager
和ISerialPort
并在CUT中使用它:
ISerialPort[] fakePorts = new MySerialPort[10];
// create your fake ports here and setup methods according to your needs
int openedPorts = 0; // just an example, I don't know what you are going to test
Mock<ISerialPort> port1Stub = new Mock<ISerialPort>();
port1Stub.Setup(p => p.Open()).Callback(() => openedPorts++);
fakePorts[0] = port1Stub.Object;
Mock<IPortManager> managerStub = new Mock<IPortManager>();
managerStub.Setup(m => m.Port).Returns(fakePorts);
TestClass cut = new TestClass();
cut.SomeMagicRoutine(managerStub.Object);