具有 WCF 调用的单元测试服务 (MSUnit + Moq)
我是 Mocking 的新手,对单元测试有些熟悉,最后决定硬着头皮开始一个采用严格 TDD 方法的新项目。然而,我有一个服务类和方法,我需要回顾性地添加测试,因为它是从原型升级的。
我不知道从哪里开始,但在这个特定的测试中,这是所涉及的类和方法:
public class PageService : IPageService
{
private readonly ITestService testServiceClient;
public PageService(ITestService testServiceClient)
{
this.testServiceClient = testServiceClient;
}
public Page GetPage(Guid websiteId, string pageKey)
{
Page builtPage = null;
// WCF SERVICE CALL I DO NOT WANT EXECUTING WHEN RUNNING UNIT TEST
// BUT RATHER WANT A BLANK NEW INSTANCE OF "PAGE" CREATED USING MOQ??
var page = testServiceClient.GetPage(websiteId, pageKey);
if (page == null)
return null;
builtPage = new Page();
[code here to build builtPage if input params ok] ...
return builtPage;
}
}
我正在努力做的是编写一个测试,希望从此我可以扩展 GetPage(.. .)
测试,但对于第一个测试,只需测试是否传入了有效的 websiteId
和 pageKey
,如果是,则接收有效的 Page< /code> 实例返回并在单元测试中断言 true。
testServiceClient
是一个 WCF 服务客户端,它之前被包装在 using()
语句中,但我已将其移出该语句,希望能够通过依赖注入来实现它,如下所示我觉得这将是测试所需的第一步,据我了解,我需要给它一个假/嘲笑? wcf 客户端而不是 testServiceClient.GetPage()
返回已知的内存数据集?希望我走在正确的轨道上。
所以这是我的单元测试的初始蓝图(我使用 Moq 框架,如果您还没有使用最新版本,Setup()
是 Expect()
的新版本起订量):
/// <summary>
/// Tests service returns a valid instance of type `Page` when a valid website and valid page key is tested.
/// </summary>
[TestMethod]
public void Test_Valid_Website_And_Valid_PageKey_Returns_Valid_Instance_Of_Page()
{
// Arrange
Page page = null;
// Act
var newPage = new Page() { Title = "Mocked Version!?"};
testServiceClient = new Mock<ITestService>();
testServiceClient.Setup(x => x.GetPage(websiteId, "about-us")).Returns(newPage);
service = new PageService(testServiceClient.Object);
page = service.GetPage(websiteId, "about-us");
// Assert
Assert.IsInstanceOfType(page, typeof(Page), "Object was not of expected instance type.");
}
我不知道从这里该去哪里,或者我是否走在正确的道路上?我可以确认上面没有语法错误,并且我确实收到了一个异常:
System.ArgumentException: Invalid setup on a non-overridable member:
x => x.GetPage(websiteId, "about-us").
我所知道的是我希望我的 service.GetPage(...)
返回一个新实例,如 websiteId
和 pageKey
是有效的,但是我不希望它使用真正的 testServiceClient.GetPage()
WCF 调用...希望我理解这个想法正确地嘲笑。当您在该服务上使用 testServiceClient.GetPage
时,我是否通过 Moq 正确告知了它,实际上只是返回一个新的页面实例?
非常感谢任何澄清!谢谢你们!
I am new to Mocking and somewhat familiar with unit testing and finally have decided to bite the bullet on a new project starting up front with a strict TDD approach. However I have one service class and method I need to retrospectively add tests to as it has been promoted from a prototype.
I do not know where to start though on this particular test, this is the classes and methods involved:
public class PageService : IPageService
{
private readonly ITestService testServiceClient;
public PageService(ITestService testServiceClient)
{
this.testServiceClient = testServiceClient;
}
public Page GetPage(Guid websiteId, string pageKey)
{
Page builtPage = null;
// WCF SERVICE CALL I DO NOT WANT EXECUTING WHEN RUNNING UNIT TEST
// BUT RATHER WANT A BLANK NEW INSTANCE OF "PAGE" CREATED USING MOQ??
var page = testServiceClient.GetPage(websiteId, pageKey);
if (page == null)
return null;
builtPage = new Page();
[code here to build builtPage if input params ok] ...
return builtPage;
}
}
What I am endeavouring to do, is write one test, from this hopefully I can expand out all permutations of GetPage(...)
tests, but for the first one simply test if a valid websiteId
and pageKey
has been passed in, if so receive a valid Page
instance back and assert true to the unit test.
testServiceClient
is a WCF service client, this was wrapped in a using()
statement before, but I have moved it out of that in hope to get it going with dependency injection as I feel that will be the first step required for testing, as from what I understand, I will need to give it a fake / mocked? wcf client instead where testServiceClient.GetPage()
returns a known in-memory set of data? Hopefully I am on the right track there.
So here is my initial blueprints of my unit test (I am using Moq framework, Setup()
is the new version of Expect()
if you haven't used latest ver of Moq):
/// <summary>
/// Tests service returns a valid instance of type `Page` when a valid website and valid page key is tested.
/// </summary>
[TestMethod]
public void Test_Valid_Website_And_Valid_PageKey_Returns_Valid_Instance_Of_Page()
{
// Arrange
Page page = null;
// Act
var newPage = new Page() { Title = "Mocked Version!?"};
testServiceClient = new Mock<ITestService>();
testServiceClient.Setup(x => x.GetPage(websiteId, "about-us")).Returns(newPage);
service = new PageService(testServiceClient.Object);
page = service.GetPage(websiteId, "about-us");
// Assert
Assert.IsInstanceOfType(page, typeof(Page), "Object was not of expected instance type.");
}
I have no idea where to go from here, or if I am on the right track? I can confirm the above has no syntax errors, and I do receive an exception:
System.ArgumentException: Invalid setup on a non-overridable member:
x => x.GetPage(websiteId, "about-us").
All I know is that I want my service.GetPage(...)
to return a new instance, as websiteId
and pageKey
was valid, however I don't want it to use the real testServiceClient.GetPage()
WCF call... hopefully I understand the idea of mocking correctly. Have I told it correctly through Moq when you use testServiceClient.GetPage
on that service, actually just return a new instance of page?
Any clarification is greatly appreciated! Thanks guys!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我想说你走在正确的道路上。如果 ITestService 确实是一个接口(如其名称所示),您将能够模拟它。
但是,当您定义设置时,Moq 必须能够识别您所指的方法,并且似乎您以某种方式指示了接口上不存在的方法。
您没有向我们展示 ITestService 接口,我们也不知道
websiteId
变量的类型。如果您仔细查看 Setup 方法,您会发现它实际上是一个泛型方法,因此当您在没有泛型参数的情况下调用它时,会进行类型推断。
我的猜测是
websiteId
的声明在某种程度上与 GetPage 的声明发生冲突。例如,如果websiteId
被声明为object
,Moq 将处理具有此签名的方法:这与在任何情况下都不一样
,一旦您设法让安装程序正常工作,您关于单元测试的基本想法似乎不错。您可以做的不仅仅是断言实例不为空,因为模拟将确保返回的实例与您最初设置的实例相同:
请注意更有价值的断言。
I would say that you are on the right track. If ITestService truly is an interface (as indicated by its name), you will be able to Mock it.
However, when you define your Setups, Moq must be able to identify which method you meant, and it seems as though you somehow indicate a method that doesn't exist on the interface.
You didn't show us the ITestService interface, and neither do we know the type of the
websiteId
variable.If you take a closer look at the Setup method you will see that it's really a generic method, so there's type inferencing going on when you call it without the generic parameters.
My guess is that the declaration of
websiteId
somehow clashes with the declaration of GetPage. If, for example,websiteId
was declared asobject
, Moq would look after a method with this signature:which isn't the same as
In any case, once you manage to get the Setup to work, your basic idea about the unit test seems fine. You can do more than just asserting that the instance isn't null, because the Mock will ensure that the instance returned is the same as the instance you originall set up:
Notice the much more valuable Assert.