忍受我,我是NUnit的新手。我来自Rails之地,所以其中一些对我来说是新的。
我有一行代码如下:
var code = WebSiteConfiguration.Instance.getCodeByCodeNameAndType("CATALOG_Brands_MinQty", item.Catalog);
我正试图嘲笑它,假设code
已经初始化了):
var _websiteConfigurationMock = new DynamicMock(typeof(WebSiteConfiguration));
_websiteConfigurationMock.ExpectAndReturn("getCodeByCodeNameAndType", code);
当我调试测试时,getCodeByCodeNameAndType
正在返回null
,而不是预期的code
。我做错了什么?
NUnit版本:2.2.8
答案 0 :(得分:7)
我很抱歉,但我从未使用过NUnit.Mocks - 但我确实对NMock和Moq有一些经验[顺便说一下,我强烈推荐]。通常,您使用模拟库来生成接口定义的代理,我假设NUnit.Mocks以相同的方式运行。
因此,如果您想嘲笑您的单身人士,您可能需要执行以下操作,
一个。创建一个界面,比如说
// All methods you would like to mock from this class, should
// be members of this interface
public interface IWebSiteConfiguration
{
// Should match signature of method you are mocking
CodeType getCodeByCodeNameAndType (
string codeString,
CatalogType catalogType);
}
湾“实施”界面
// You've already written the method, interface matches signature,
// should be as easy as slapping interface on class declaration
public class WebSiteConfiguration : IWebSiteConfiguration { }
℃。消费界面
好的,所以步骤c。是你大部分工作的地方。从逻辑上讲,如果你在嘲笑你的单身人士,你实际上是对消费者进行单元测试[你已经从你的样本中留下了]。对于c。只需将一个参数添加到使用者的ctor中,或添加Type'IWebSiteConfiguration'的可公开访问的属性,然后在内部引用实例成员并针对此新接口调用您的方法。考虑一下,是
public class MyClass
{
public MyClass () { }
public void DoSomething ()
{
// bad singleton! bad boy! static references are bad! you
// can't change them! convenient but bad!
code = WebSiteConfiguration.Instance.getCodeByCodeNameAndType (
"some.string",
someCatalog)
}
}
变为
public class MyClass
{
private readonly IWebSiteConfiguration _config = null;
// just so you don't break any other code, you can default
// to your static singleton on a default ctor
public MyClass () : this (WebSiteConfiguration.Instance) { }
// new constructor permits you to swap in any implementation
// including your mock!
public MyClass (IWebSiteConfiguration config)
{
_config = config;
}
public void DoSomething ()
{
// huzzah!
code = _config.getCodeByCodeNameAndType ("some.string", someCatalog)
}
}
在您的单元测试中,创建模拟,将模拟的引用传递给使用者,并测试使用者。
[Test]
public void Test ()
{
IWebSiteConfiguration mockConfig = null;
// setup mock instance and expectation via
// NUnit.Mocks, NMock, or Moq
MyClass myClass = new MyClass (mockConfig);
myClass.DoSomething ();
// verify results
}
这也是依赖注入[DI]的实用介绍。这只是向服务提供者传递或“注入”服务引用[例如您的网站配置类]的做法,而不是让消费者直接调用服务[例如通过静态单例类]。
希望这会有所帮助:)
答案 1 :(得分:1)
DynamicMock在内存中创建一个新对象,表示要模拟的接口或marshallable(继承自MarshalByRef)类。
试试这个:
var _websiteConfigurationMock = new DynamicMock(typeof(WebSiteConfiguration));
_websiteConfigurationMock.ExpectAndReturn("getCodeByCodeNameAndType", code);
WebSiteConfiguration conf = (WebSiteConfiguration)_websiteConfigurationMock.MockInstance;
var x = conf.getCodeByCodeNameAndType("CATALOG_Brands_MinQty", item.Catalog);
请注意,除非WebSiteConfiguration继承MarshalByRef,否则第三行将无效。
你通常做的是模拟一个接口并获得一个实现这个接口的新对象,但是按照你配置它的方式行事,而不必为它做一个具体的类型,所以我不是除非你使用更好的隔离框架,比如可以拦截对现有对象中的静态方法/属性的调用的TypeMock,否则完全确定你正在做的是什么。
答案 2 :(得分:1)
似乎有一种使用反射的解决方案,或者我可能完全误解了这一点。
这里讨论: http://www.geekbeing.com/2010/05/23/how-to-unit-test-singleton-hack-in-c
真的有用吗?
public class TestableSingleton : SingletonClass
{
public TestableSingleton ()
{
FieldInfo fieldInfo = typeof(SingletonClass)
.GetField("_instance",
BindingFlags.Static | BindingFlags.NonPublic);
fieldInfo.SetValue(Instance, this);
}
}
项目可在https://github.com/rbabreu/TestableSingleton
上找到实际上我无法在Visual Studio上编译它,因为SingletonClass会有一个私有构造函数。如果有人让它工作将是很好的,以避免适配器模式的开销。