我看过很多关于“Mocking a private method”的帖子和问题,但仍然无法让它工作,也没有找到真正的答案。 让我们忘记代码的味道,你不应该这样做等等......
据我所知,我做了以下事情:
1) 创建了一个类库“MyMoqSamples”
2) 添加了对 Moq 和 NUnit 的引用
3) 编辑 AssemblyInfo 文件并添加 [装配:InternalsVisibleTo(“DynamicProxyGenAssembly2”)] [程序集:InternalsVisibleTo("MyMoqSamples")]
4) 现在需要测试一个私有(private)方法。因为它是一个私有(private)方法,所以它不是接口(interface)的一部分。
5) 添加了以下代码
[TestFixture]
public class Can_test_my_private_method
{
[Test]
public void Should_be_able_to_test_my_private_method()
{
// TODO how do I test my DoSomthing method?
}
}
public class CustomerInfo
{
public string Name { get; set; }
public string Surname { get; set; }
}
public interface ICustomerService
{
List<CustomerInfo> GetCustomers();
}
public class CustomerService : ICustomerService
{
public List<CustomerInfo> GetCustomers()
{
return new List<CustomerInfo> { new CustomerInfo { Surname = "Bloggs", Name = "Jo" } };
}
protected virtual void DoSomething()
{
}
}
您能否提供一个示例,说明您将如何测试我的私有(private)方法? 非常感谢
最佳答案
您描述的步骤将 Moq 设置为测试内部类和成员,因此与测试 protected 或私有(private)方法没有任何关系
测试私有(private)方法有点难闻,你真的应该只测试公共(public) API。如果您觉得该方法真的很重要并且需要单独测试,也许它应该放在自己的类中,然后可以单独测试它?
如果您打算测试上面的 protected 方法,您可以在测试程序集中使用自己的 Mock:
public class CustomerServiceMock : CustomerService {
public void DoSomethingTester() {
// Set up state or whatever you need
DoSomething();
}
}
[TestMethod]
public void DoSomething_WhenCalled_DoesSomething() {
CustomerServiceMock serviceMock = new CustomerServiceMock(...);
serviceMock.DoSomethingTester();
}
如果它是私有(private)的,你可能会用反射做一些狡猾的事情,但走这条路是测试 hell 的方式。
更新
虽然您在问题中提供了示例代码,但我真的不明白您想如何“测试” protected 方法,所以我会想出一些人为的方法...
假设您的客户服务是这样的:-
public CustomerService : ICustomerService {
private readonly ICustomerRepository _repository;
public CustomerService(ICustomerRepository repository) {
_repository = repository;
}
public void MakeCustomerPreferred(Customer preferred) {
MakePreferred(customer);
_repository.Save(customer);
}
protected virtual void MakePreferred(Customer customer) {
// Or more than likely some grungy logic
customer.IsPreferred = true;
}
}
如果你想测试 protected 方法,你可以这样做:-
[TestClass]
public class CustomerServiceTests {
CustomerServiceTester customerService;
Mock<ICustomerRepository> customerRepositoryMock;
[TestInitialize]
public void Setup() {
customerRepoMock = new Mock<ICustomerRepository>();
customerService = new CustomerServiceTester(customerRepoMock.Object);
}
public class CustomerServiceTester : CustomerService {
public void MakePreferredTest(Customer customer) {
MakePreferred(customer);
}
// You could also add in test specific instrumentation
// by overriding MakePreferred here like so...
protected override void MakePreferred(Customer customer) {
CustomerArgument = customer;
WasCalled = true;
base.MakePreferred(customer);
}
public Customer CustomerArgument { get; set; }
public bool WasCalled { get; set; }
}
[TestMethod]
public void MakePreferred_WithValidCustomer_MakesCustomerPreferred() {
Customer customer = new Customer();
customerService.MakePreferredTest(customer);
Assert.AreEqual(true, customer.IsPreferred);
}
// Rest of your tests
}
此“模式”的名称是测试特定子类(基于 xUnit 测试模式术语),您可能希望在此处查看更多信息:-
http://xunitpatterns.com/Test-Specific%20Subclass.html
根据您的评论和之前的问题,您似乎接到了对某些遗留代码实现单元测试的任务(或者您自己做出了决定)。在这种情况下,遗留代码的圣经就是 Michael Feathers 的书。它涵盖了这样的技术以及重构和技术,以处理将“不可测试”的类和方法分解为更易于管理的东西,我强烈推荐它。
关于c# - 测试和模拟私有(private)/ protected 方法。许多帖子,但仍然无法使一个示例起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2979426/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何
我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>
我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当
我有一个围绕一些对象的包装类,我想将这些对象用作散列中的键。包装对象和解包装对象应映射到相同的键。一个简单的例子是这样的:classAattr_reader:xdefinitialize(inner)@inner=innerenddefx;@inner.x;enddef==(other)@inner.x==other.xendenda=A.new(o)#oisjustanyobjectthatallowso.xb=A.new(o)h={a=>5}ph[a]#5ph[b]#nil,shouldbe5ph[o]#nil,shouldbe5我试过==、===、eq?并散列所有无济于事。
我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere
是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou