单元测试扩展方法
我们的团队刚刚开始单元测试和模拟,并且我们已经就扩展方法进行了一些讨论。 问题是使用扩展方法来测试类的好方法是什么。 即我们有一个像这样的枚举..
public enum State
{
[LangID(2817)]
Draft = 0,
[LangID(2832)]
Booked = 1,
[LangID(1957)]
Overdue = 2,
[LangID(2834)]
Checked = 3,
}
它使用了扩展方法:
public static string GetDescription(this Enum _enum)
{
Type type = _enum.GetType();
MemberInfo[] memInfo = type.GetMember(_enum.ToString());
if (memInfo != null && memInfo.Length > 0)
{
object[] attrs = memInfo[0].GetCustomAttributes(typeof(LangID), false);
if (attrs != null && attrs.Length > 0)
return LanguageDB.GetString(((LangID)attrs[0]).ID);
}
return _enum.ToString();
}
它将再次由被测试的类调用,就像这样..
public class SUT(){
public void MethodUnderTest(){
string description = SomeObject.Status.GetDescription();//Status is Type State
}
}
在此示例中,枚举通过 LanguageDB 获取用户语言的描述,不幸的是它没有注入到类中,因为它是静态的。 我们自然可以折射这批数据,但这将是一笔巨大的投资,因为代码几乎完美无缺。 有什么好的建议吗?
Our team has just started unittesting and mocking, and we have run into some discussion considering extension methods. The question is what is a good approach to testing classes, that make use of extension methods. I.e. we have an Enum like this..
public enum State
{
[LangID(2817)]
Draft = 0,
[LangID(2832)]
Booked = 1,
[LangID(1957)]
Overdue = 2,
[LangID(2834)]
Checked = 3,
}
Which makes use of the extension method:
public static string GetDescription(this Enum _enum)
{
Type type = _enum.GetType();
MemberInfo[] memInfo = type.GetMember(_enum.ToString());
if (memInfo != null && memInfo.Length > 0)
{
object[] attrs = memInfo[0].GetCustomAttributes(typeof(LangID), false);
if (attrs != null && attrs.Length > 0)
return LanguageDB.GetString(((LangID)attrs[0]).ID);
}
return _enum.ToString();
}
Which again will be called by the class under test, like so ..
public class SUT(){
public void MethodUnderTest(){
string description = SomeObject.Status.GetDescription();//Status is Type State
}
}
In this example the enum is getting a description in the language of the user, via LanguageDB, which unfortunately is not injected inside the class since it's static. We could naturally refractor the lot, but this would be a big investment, considering the code is working almost flawless.
Any good suggestion?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
如果您使用 MS 的测试套件,您可以进行非常简单的重构,并能够使用访问器将模拟注入静态类型对象。
假设您有这样的代码:
静态中的静态...难以测试? 并不真地。 如此修改扩展类:
简单重构。 现在,您可以使用访问器在测试时设置您的模拟......
If you're using MS' test suite you can do a very simple refactoring and be able to use Accessors to inject a mock into your static type object.
Let's say you've got code like this:
A static within a static... hard to test? Not really. Modify the extension class thusly:
Simple refactor. Now, you can use the accessor to set your mock at test time...
测试扩展方法本身的一个想法是使用一个私有方法来完成注入 LanguageDB 的所有工作。 公共方法将使用静态 LanguageDB 调用私有方法,但实际上您将通过反射测试私有方法并传入模拟对象。
至于测试被测的实际类,您可能需要想出一种方法来替换静态 LanguageDB——也许只是将其清空并测试您是否获得了实际的枚举名称。 毕竟,您已经在其他地方测试了该扩展是否有效,因此您实际上不需要在此类中再次测试它。
最终,您会发现静态对象很难测试。 正如您已经猜到的那样,真正的答案是重构为更好的设计,如果可以避免静态对象,则不依赖它们(尽管这似乎是一个不错的选择)。 也许,您可以通过重构来包含注入。
One idea for testing the extension method itself would be to have a private method that does all the work that does get the LanguageDB injected. The public method would call the private method with the static LanguageDB, but you would actually test the private method via reflection and pass in a mock object.
As for testing the actual class under test, you'll probably need to come up with a way to replace the static LanguageDB -- perhaps just null it out and test that you are getting the actual enum names. After all, you've already tested that the extension works elsewhere so you don't really need to test it again in this class.
Ultimately, you're finding out that static objects are hard to test. The real answer, as you've already guessed, is to refactor to a better design that doesn't rely on static objects if they can be avoided (though this does seem to be a good candidate). Perhaps, you can get by just refactoring to include injection.
几乎完美无缺? ;-)
规则 1:如果无法测试,就不要编写它。
规则2:生活中的许多事情看起来都会受到伤害,但其实不然。
您有多确定这次重构将是一项巨大的投资?
规则0:规则是为智者提供指导,为白痴提供服从的。
这是一个判断,您通过工作避免该方法中的缺陷的可能性有多大? 我的猜测是,在这种情况下,重构该方法的好处非常小。
almost flawless? ;-)
Rule 1: If it can't be tested don't write it.
Rule 2: Many things is life look like tehy are going to hurt, but don't.
How sure are you that this refactoring is going to be a big investment?
Rule 0: Rules are for the guidance of Wise Men and ond the obedience of Idiots.
This is a judgement call how likely are you avoid a defect in that method by the work? My guess is that in this case the benefits of refactoring that method are quite small.