Java 如何单元测试抽象类:用存根扩展?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/243274/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to unit test abstract classes: extend with stubs?
提问by Paul Whelan
I was wondering how to unit test abstract classes, and classes that extend abstract classes.
我想知道如何对抽象类和扩展抽象类的类进行单元测试。
Should I test the abstract class by extending it, stubbing out the abstract methods, and then test all the concrete methods? Then only test the methods I override, and test the abstract methods in the unit tests for objects that extend my abstract class?
我应该通过扩展抽象类来测试抽象类,剔除抽象方法,然后测试所有具体方法吗?然后只测试我覆盖的方法,并在单元测试中测试扩展我的抽象类的对象的抽象方法?
Should I have an abstract test case that can be used to test the methods of the abstract class, and extend this class in my test case for objects that extend the abstract class?
我是否应该有一个抽象测试用例来测试抽象类的方法,并在我的测试用例中为扩展抽象类的对象扩展这个类?
Note that my abstract class has some concrete methods.
请注意,我的抽象类有一些具体的方法。
采纳答案by Patrick Desjardins
Write a Mock object and use them just for testing. They usually are very very very minimal (inherit from the abstract class) and not more.Then, in your Unit Test you can call the abstract method you want to test.
编写一个 Mock 对象并将它们用于测试。它们通常非常非常小(从抽象类继承)而不是更多。然后,在您的单元测试中,您可以调用要测试的抽象方法。
You should test abstract class that contain some logic like all other classes you have.
您应该像您拥有的所有其他类一样测试包含某些逻辑的抽象类。
回答by casademora
I would argue against "abstract" tests. I think a test is a concrete idea and doesn't have an abstraction. If you have common elements, put them in helper methods or classes for everyone to use.
我会反对“抽象”测试。我认为测试是一个具体的想法,没有抽象。如果你有共同的元素,把它们放在辅助方法或类中供每个人使用。
As for testing an abstract test class, make sure you ask yourself what it is you're testing. There are several approaches, and you should find out what works in your scenario. Are you trying to test out a new method in your subclass? Then have your tests only interact with that method. Are you testing the methods in your base class? Then probably have a separate fixture only for that class, and test each method individually with as many tests as necessary.
至于测试抽象测试类,一定要问自己要测试的是什么。有几种方法,您应该找出在您的场景中有效的方法。您是否正在尝试在您的子类中测试新方法?然后让您的测试仅与该方法交互。您是否正在测试基类中的方法?然后可能只有该类的单独夹具,并根据需要使用尽可能多的测试单独测试每个方法。
回答by Jeb
If the concrete methods invoke any of the abstract methods that strategy won't work, and you'd want to test each child class behavior separately. Otherwise, extending it and stubbing the abstract methods as you've described should be fine, again provided the abstract class concrete methods are decoupled from child classes.
如果具体方法调用任何抽象方法,该策略将不起作用,并且您希望分别测试每个子类的行为。否则,扩展它并存根您所描述的抽象方法应该没问题,再次提供抽象类的具体方法与子类分离。
回答by Ace
I suppose you could want to test the base functionality of an abstract class... But you'd probably be best off by extending the class without overriding any methods, and make minimum-effort mocking for the abstract methods.
我想你可能想要测试一个抽象类的基本功能......但是你最好通过扩展类而不覆盖任何方法,并对抽象方法进行最小的模拟。
回答by Ace
To make an unit test specifically on the abstract class, you should derive it for testing purpose, test base.method() results and intended behaviour when inheriting.
要专门对抽象类进行单元测试,您应该派生它用于测试目的,在继承时测试 base.method() 结果和预期行为。
You test a method by calling it so test an abstract class by implementing it...
你通过调用一个方法来测试它,所以通过实现它来测试一个抽象类......
回答by Mnementh
What I do for abstract classes and interfaces is the following: I write a test, that uses the object as it is concrete. But the variable of type X (X is the abstract class) is not set in the test. This test-class is not added to the test-suite, but subclasses of it, that have a setup-method that set the variable to a concrete implementation of X. That way I don't duplicate the test-code. The subclasses of the not used test can add more test-methods if needed.
我对抽象类和接口所做的如下:我编写了一个测试,它使用具体的对象。但是测试中没有设置X类型的变量(X是抽象类)。这个测试类没有添加到测试套件中,而是它的子类,它们有一个设置方法,可以将变量设置为 X 的具体实现。这样我就不会复制测试代码。如果需要,未使用测试的子类可以添加更多测试方法。
回答by Patrick Desjardins
This is the pattern I usually follow when setting up a harness for testing an abstract class:
这是我在设置用于测试抽象类的工具时通常遵循的模式:
public abstract class MyBase{
/*...*/
public abstract void VoidMethod(object param1);
public abstract object MethodWithReturn(object param1);
/*,,,*/
}
And the version I use under test:
我在测试中使用的版本:
public class MyBaseHarness : MyBase{
/*...*/
public Action<object> VoidMethodFunction;
public override void VoidMethod(object param1){
VoidMethodFunction(param1);
}
public Func<object, object> MethodWithReturnFunction;
public override object MethodWithReturn(object param1){
return MethodWihtReturnFunction(param1);
}
/*,,,*/
}
If the abstract methods are called when I don't expect it, the tests fail. When arranging the tests, I can easily stub out the abstract methods with lambdas that perform asserts, throw exceptions, return different values, etc.
如果抽象方法在我不期望的时候被调用,测试就会失败。在安排测试时,我可以很容易地用 lambda 来删除抽象方法,这些方法执行断言、抛出异常、返回不同的值等。
回答by bryanbcook
One of the main motivations for using an abstract class is to enable polymorphism within your application -- i.e: you can substitute a different version at runtime. In fact, this is very much the same thing as using an interface except the abstract class provides some common plumbing, often referred to as a Template pattern.
使用抽象类的主要动机之一是在您的应用程序中启用多态性——即:您可以在运行时替换不同的版本。事实上,这与使用接口非常相似,只是抽象类提供了一些常见的管道,通常称为模板模式。
From a unit testing perspective, there are two things to consider:
从单元测试的角度来看,有两件事需要考虑:
Interaction of your abstract class with it related classes. Using a mock testing framework is ideal for this scenario as it shows that your abstract class plays well with others.
Functionality of derived classes. If you have custom logic that you've written for your derived classes, you should test those classes in isolation.
抽象类与其相关类的交互。使用模拟测试框架非常适合这种情况,因为它表明您的抽象类与其他类兼容良好。
派生类的功能。如果您为派生类编写了自定义逻辑,则应单独测试这些类。
edit: RhinoMocks is an awesome mock testing framework that can generate mock objects at runtime by dynamically deriving from your class. This approach can save you countless hours of hand-coding derived classes.
编辑:RhinoMocks 是一个很棒的模拟测试框架,它可以通过从您的类动态派生在运行时生成模拟对象。这种方法可以为您节省无数小时的手工编码派生类。
回答by Seth Petry-Johnson
If your abstract class contains concrete functionality that has business value, then I will usually test it directly by creating a test double that stubs out the abstract data, or by using a mocking framework to do this for me. Which one I choose depends a lot on whether I need to write test-specific implementations of the abstract methods or not.
如果您的抽象类包含具有商业价值的具体功能,那么我通常会通过创建一个测试替身来直接测试它,以提取抽象数据,或者使用模拟框架为我执行此操作。我选择哪一个很大程度上取决于我是否需要编写抽象方法的特定于测试的实现。
The most common scenario in which I need to do this is when I'm using the Template Method pattern, such as when I'm building some sort of extensible framework that will be used by a 3rd party. In this case, the abstract class is what defines the algorithm that I want to test, so it makes more sense to test the abstract base than a specific implementation.
我需要这样做的最常见场景是当我使用模板方法模式时,例如当我构建某种将由 3rd 方使用的可扩展框架时。在这种情况下,抽象类定义了我要测试的算法,因此测试抽象基比测试特定实现更有意义。
However, I think it's important that these tests should focus on the concrete implementations of real business logic only; you shouldn't unit test implementation detailsof the abstract class because you'll end up with brittle tests.
但是,我认为这些测试应该只关注真实业务逻辑的具体实现,这一点很重要;你不应该对抽象类的实现细节进行单元测试,因为你最终会得到脆弱的测试。
回答by Ray Tayek
one way is to write an abstract test case that corresponds to your abstract class, then write concrete test cases that subclass your abstract test case. do this for each concrete subclass of your original abstract class (i.e. your test case hierarchy mirrors your class hierarchy). see Test an interface in the junit recipies book: http://safari.informit.com/9781932394238/ch02lev1sec6.
一种方法是编写一个与您的抽象类相对应的抽象测试用例,然后编写具体的测试用例来继承您的抽象测试用例。对原始抽象类的每个具体子类执行此操作(即,您的测试用例层次结构反映了您的类层次结构)。请参阅在 junit 食谱书中测试接口:http://safari.informit.com/9781932394238/ch02lev1sec6 。
also see Testcase Superclass in xUnit patterns: http://xunitpatterns.com/Testcase%20Superclass.html
另请参阅 xUnit 模式中的测试用例超类:http: //xunitpatterns.com/Testcase%20Superclass.html