Java 模拟抽象方法,但不模拟类构造函数
我有一个场景,其中我有一个类似于下面的抽象类。我想模拟通过构造函数提供的Java 模拟抽象方法,但不模拟类构造函数,java,unit-testing,mockito,Java,Unit Testing,Mockito,我有一个场景,其中我有一个类似于下面的抽象类。我想模拟通过构造函数提供的RandomNumberGenerator实例,并编写一个单元测试来测试doSomethingRandomLotsOfTimes方法中的逻辑 有没有一种方法可以用mockito/另一个框架实现这一点 public abstract class MyClass { private final RandomNumberGenerator randomNumberGenerator; public MyClas
RandomNumberGenerator
实例,并编写一个单元测试来测试doSomethingRandomLotsOfTimes
方法中的逻辑
有没有一种方法可以用mockito/另一个框架实现这一点
public abstract class MyClass {
private final RandomNumberGenerator randomNumberGenerator;
public MyClass(RandomNumberGenerator randomNumberGenerator) {
this.randomNumberGenerator = randomNumberGenerator;
}
public abstract void doSomething(int x);
public void doSomethingRandomLotsOfTimes() {
for(int i=0; i<10; i++) {
int r = randomNumberGenerator.next();
doSomething(r);
}
}
}
无法直接实例化抽象类。 必须实例化扩展抽象类的非抽象类 声明一个非抽象类,该类扩展单元测试类中的抽象类(例如
公共静态类blam extends MyClass
),并提供所有抽象方法的空实现
一旦你有了一个可以实例化的类,
创建RandomNumberGenerator类的间谍。
spy允许您测试spy中的方法是否被调用
创建
blam
的实例,并将spy RandomNumberGenerator作为构造函数参数传递。无法直接实例化抽象类。
必须实例化扩展抽象类的非抽象类
声明一个非抽象类,该类扩展单元测试类中的抽象类(例如公共静态类blam extends MyClass
),并提供所有抽象方法的空实现
一旦你有了一个可以实例化的类,
创建RandomNumberGenerator类的间谍。
spy允许您测试spy中的方法是否被调用
创建
bum
的实例,并将spy RandomNumberGenerator作为构造函数参数传递。您的类更容易通过组合实现:
public final class MyClass {
private final RandomNumberGenerator randomNumberGenerator;
private final IntConsumer somethingDoer;
public MyClass(
RandomNumberGenerator randomNumberGenerator,
IntConsumer somethingDoer) {
this.randomNumberGenerator = randomNumberGenerator;
this.somethingDoer = somethingDoer;
}
public void doSomethingRandomLotsOfTimes() {
for(int i=0; i<10; i++) {
int r = randomNumberGenerator.next();
somethingDoer.consume(r);
}
}
}
公共最终类MyClass{
私人最终RandomNumberGenerator RandomNumberGenerator;
私人最终消费者或某些行为人;
公共MyClass(
RandomNumberGenerator RandomNumberGenerator,
IntConsumer something doer){
this.randomNumberGenerator=randomNumberGenerator;
this.somethingDoer=somethingDoer;
}
公共无效dosomethin grandomlotsoftimes(){
对于(int i=0;i,您的类更容易通过组合实现:
public final class MyClass {
private final RandomNumberGenerator randomNumberGenerator;
private final IntConsumer somethingDoer;
public MyClass(
RandomNumberGenerator randomNumberGenerator,
IntConsumer somethingDoer) {
this.randomNumberGenerator = randomNumberGenerator;
this.somethingDoer = somethingDoer;
}
public void doSomethingRandomLotsOfTimes() {
for(int i=0; i<10; i++) {
int r = randomNumberGenerator.next();
somethingDoer.consume(r);
}
}
}
公共最终类MyClass{
私人最终RandomNumberGenerator RandomNumberGenerator;
私人最终消费者或某些行为人;
公共MyClass(
RandomNumberGenerator RandomNumberGenerator,
IntConsumer something doer){
this.randomNumberGenerator=randomNumberGenerator;
this.somethingDoer=somethingDoer;
}
公共无效dosomethin grandomlotsoftimes(){
对于(int i=0;i@OleksandrShpota我认为这是一个不同的问题,因为这些问题不涉及需要模拟的构造函数参数。为什么需要模拟这个类?使用真实的类,使用模拟的RNG。此外,这看起来像是一个组合应该优先于继承的示例:doSomething
只是一个:传递然后你可以对IntConsumer
进行单元测试,MyClass
调用IntConsumer
的单元测试。我宁愿把这个类中特定于逻辑的测试放在MyClassTest
中,让子类的测试只考虑它们自身的逻辑“我宁愿在这个类中保留特定于逻辑的测试"这就支持了Andy对合成优于继承的建议。让它成为一个真正的类,给方法doSomethingRandomLotsOfTimes
一个函数接口参数,并将其作为依赖项传递给需要它的类。@OleksandrShpota我认为这是有区别的,因为这些问题不涉及构造函数参数要模拟的ds为什么需要模拟此类?使用带有模拟RNG的真实类。此外,这似乎是一个组合优先于继承的示例:doSomething
只是一个:将其中一个传递到构造函数中。然后可以对IntConsumer
进行单元测试,并对MyC进行单元测试lass
调用IntConsumer
。我宁愿将此类中特定于逻辑的测试保留在MyClassTest
中,而让子类的测试只关心其自身的逻辑“我宁愿将特定于逻辑的测试保留在此类中”这就支持了Andy关于组合优于继承的建议。将thid作为一个真正的类,给方法doSomethingRandomLotsOfTimes
一个函数接口参数,并将其作为依赖项传递给需要它的类。我很想测试MyClass中的逻辑如何处理doSomething()的一些场景抛出异常等,您描述的方法是否可能?@Ed0906当然,只需实现抽象方法来抛出异常。您可以使用以下方法创建模拟:MyClass MyClass=mock(MyClass.class,Mockito.CALLS_REAL_METHODS);
来抛出异常:doThrow(new exception()).when(MyClass.doSomething(anyInt())
一旦你有了spy,它与Hugo提到的模拟调用_Real_方法完全一样。有了spy,你可以模拟单个方法并根据需要抛出。我很想测试一些场景,看看MyClass中的逻辑如何处理doSomething()抛出异常等,您描述的方法是否可能?@Ed0906当然,只需实现抽象方法来抛出异常。您可以使用以下方法创建模拟:MyClass MyClass=mock(MyClass.class,Mockito.CALLS_REAL_METHODS);
来抛出异常:doThrow(new exception()).when(MyClass.doSomething(anyInt())
一旦你有了间谍,这与雨果提到的模拟呼叫和真实方法完全一样。有了间谍,你可以模拟单独的方法并根据需要投掷。非常感谢你,先生——祝你晚上愉快,晚安,并愿接下来的几天用伟大的问题来回答你!非常感谢,先生