使用mockito将模拟注入抽象类

tp5buhyn  于 2022-11-23  发布在  其他
关注(0)|答案(6)|浏览(569)

我正在嘲讽一个抽象类如下:
myAbstractClass = Mockito.mock(MyAbstractClass.class, Mockito.CALLS_REAL_METHODS);
问题是MyAbstractClass有一些依赖项是通过EJB注解注入的,并且没有setter。2有什么方法可以注入依赖项吗?
@InjectMocks不适用于抽象类别。

fwzugrvs

fwzugrvs1#

我使用junit5来完成这个任务。
我所做的是在@BeforeEach中用new abstractClass()示例化抽象类,如果方法不是抽象的,就用super调用方法(使用这个方法是因为我有protected方法),之后我用ReflectionUtils.setField()设置抽象类中的mock,测试每个方法,效果很好。我留下了一个简单的例子。
抽象类

public abstract class AbstractClass {
  @Autowired
  private Environment environment;

  protected String getProperty(String property){
    return environment.getRequiredProperty(property);
  }
}

抽象类测试

@ExtendWith(MockitoExtension.class)
class AbstractClassTest {

  AbstractClass abstractClass;

  @Mock
  Environment environment;

  @BeforeEach
  void setUp() {
    abstractClass = new AbstractClass() {
      @Override
      public String getProperty(String property) {
        return super.getProperty(property);
      }
    };
    ReflectionTestUtils.setField(abstractClass, "environment", environment);
  }

  @Test
  void shouldReturnProperty() {
    String propertyValue = "this property";
    when(environment.getRequiredProperty("property")).thenReturn(propertyValue);
    String property = abstractClass.getProperty("property");
    assertEquals(propertyValue, property);
  }
}

这只是使用mockito和junit5进行测试。记住在用new AbstractClass()示例化类之后调用ReflectionUtils,否则mock不会被注入。
对该实现的任何改进都是受欢迎的:D.

x6yk4ghg

x6yk4ghg2#

因为你不能示例化一个抽象类,所以没有什么可测试的。我建议你创建一个子类(它可以是你的测试类中的一个嵌套类),然后以这种方式运行你的测试。然后你就可以像平常一样使用@Mock@InjectMocks了。

z8dt9xmd

z8dt9xmd3#

您可以使用Powermock库在myAbstractClass中使用Whitebox.setInternalState(myAbstractClass, mock(MockedClass.class))注入模拟;

q3qa4bjr

q3qa4bjr4#

Junit 4特定解决方案
需要测试抽象类

@Slf4j
public abstract class AdhocNotificationEmail {

    @Autowired
    protected CustomerNotificationRepository customerNotificationRepository;

    protected abstract  Map<String, String> abstractMethod(AdhocNotificationDTO adhocNotificationDTO);

    public JSONObject concreteMethod(){
      // some stuff that needs to be tested and common to all subclasses
    }
}

测试类别:

@RunWith(SpringJUnit4ClassRunner.class)
public class AdhocNotificationEmailTest{

    @Mock
    protected CustomerNotificationRepository customerNotificationRepository;

    private AdhocNotificationEmail unit;

    @Before
    public void setUp() {
        unit = new AdhocNotificationEmail() {
                   @Override
                   protected Map<String, String> abstractMethod(AdhocNotificationDTO notificationDTO) {
                    return null;
                   }
               };
        unit.customerNotificationRepository = customerNotificationRepository;
    }

    @Test
    public void concreteMethod_greenPath() {
        final String templateName = "NOTIFICATION_TEMPLATE";
        final AdhocNotificationDTO adhocNotificationDTOStub = getAdhocNotificationDTOStub(templateName);
        final CustomerNotification customerNotificationStub = getCustomerNotificationStub(templateName);
        when(customerNotificationRepository.findByIdAndTemplateName(id, templateName)).thenReturn(customerNotificationStub);
        final JSONObject response = unit.concreteMethod(adhocNotificationDTOStub);
        assertNotNull(response);
    }
v1uwarro

v1uwarro5#

就我个人而言,我喜欢用一个匿名类来扩展抽象,这个匿名类在@Before(或者在junit.jupiter中是@BeforeEach)中声明。

  • 不要模拟我想要测试的类(就像你对Mockito.mock(MyAbstractClass.class, Mockito.CALLS_REAL_METHODS)所做的那样),因为这是一种反模式。
  • 您可以为抽象类的依赖项提供Mock,并且由非抽象方法调用;
  • 您可以测试调用抽象方法的非抽象方法

示例:

class TestAbstractClass {
    @Mock
    private ServiceDependency dependency;

    private AbstractClass abstractClass;

    @BeforeEach
    void setUp() {
        abstractClass= new AbstractClass (dependency) { };
    }

    @Test
    void test(){
        Mockito.when(dependency.someMethod()).thenReturn(something);
        var result = abstractclass.someNonAbstractMethod();
        // assertions
    }

}
rslzwgfq

rslzwgfq6#

好的做法是为所有可能继承此抽象类的类编写单元测试。因为理论上这是可能的情况。此依赖关系应该被模拟,并且您应该忘记模拟此EJB组件的依赖关系。也许一些代码片段将有助于澄清您试图在此处实现的目标。

相关问题