是否可以使用 Mockito 模拟静态且无效的方法?

问题描述 投票:0回答:3

我试图避免在这里使用 PowerMockito。我们有遗留代码,其中包含静态和无效的方法,并且有一些测试需要模拟它们。有没有办法做到这一点,或者重构遗留代码是唯一的方法吗?

class MySample {
       public static void sampleMethod(String argument){
                //do something
       }
}

如果我使用通用的 MockStatic 语法,它会要求我返回一些东西:

MockedStatic <MySample> sampleMock = Mockito.mockStatic( MySample.class );
sampleMock.when(() -> MySample.sampleMethod(Mockito.any(String.class)));

例外:

org.mockito.exceptions.misusing.UnfinishedStubbingException: 
Unfinished stubbing detected here:
-> at com.mytests.Test.setMock(Test.java:35)

E.g. thenReturn() may be missing.
Examples of correct stubbing:
    when(mock.isOk()).thenReturn(true);
    when(mock.isOk()).thenThrow(exception);
    doThrow(exception).when(mock).someVoidMethod();
Hints:
 1. missing thenReturn()
 2. you are trying to stub a final method, which is not supported
 3. you are stubbing the behaviour of another mock inside before 'thenReturn' instruction is completed

编辑:请注意,我正在寻找模拟一个既静态又无效的方法。

java mockito
3个回答
7
投票

当模拟方法被调用时,你希望发生什么?

默认行为是什么也不发生。 通过调用

sampleMock.when()
,您表明您想要从默认行为更改为其他行为。 Mockito 正在抱怨,因为您没有随后调用
then___()
来指定应该发生什么。

我可以想到您可能希望发生的一些不同的事情:

1.什么也不做

如前所述,这是默认行为,因此如果这就是您想要的,您可以删除第二行,它应该可以工作。 但是,如果您确实需要进行

when
调用(例如用于参数捕获),您可以使用空的
thenAnswer
来结束该行:

sampleMock.when(() -> MySample.sampleMethod(Mockito.any(String.class)))
    .thenAnswer(invocation -> null);

2.调用真正的方法

sampleMock.when(() -> MySample.sampleMethod(Mockito.any(String.class)))
    .thenCallRealMethod();

3.做点别的事吧

sampleMock.when(() -> MySample.sampleMethod(Mockito.any(String.class)))
    .thenAnswer(invocation -> {
        // insert code to do something else here
        return null;
    });

4.抛出异常

sampleMock.when(() -> MySample.sampleMethod(Mockito.any(String.class)))
    .thenThrow(RuntimeException.class);

更新

如前所述,默认行为是不执行任何操作,但我了解到还可以通过在创建模拟时提供

Answer
来指定备用默认行为。 例如,要让默认行为改为调用真实方法:

MockedStatic <MySample> sampleMock = Mockito.mockStatic( MySample.class, Mockito.CALLS_REAL_METHODS );

但要注意 - 正如 Marc 在 this answer 中所指出的,即使您覆盖默认行为,真正的方法仍然会被调用! 这可能会在未来得到修复;请参阅马克的回答以获得一些很好的参考


0
投票

@RunWith(PowerMockRunner.class)
添加到类头中将防止抛出上述异常类型!


0
投票

是的,这是可能的。 例如,我检查了

Hibernate.initialize(object)
的调用 - 它是静态且无效的。

@Table
public class Address {
    @Id
    private String id;
    ...
}

@Table
public class Person{
    @Id
    private String id;
    private processCode;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "address_id")
    private Address address;
    ...
}

我想测试

findPersons
并确保为每个找到的人调用
Hibernate.initialize

@Override
public List<KafkaFileDto> findPersons(int processCode, maxNumberOfPersons) {
    return kafkaFileRepository.findRecordsForNewKafkaSender(processCode, Pageable.ofSize(maxNumberOfPersons))
            .stream()
            .map(person-> {
                Hibernate.initialize(person.getAddress());
                return entityToDtoMapper.map(person);
            })
            .collect(Collectors.toList());
}

测试 findPersons:

    ...
    try (MockedStatic<Hibernate> hibernateMockedStatic = Mockito.mockStatic(Hibernate.class)) {
        List<Person> result = personRepository.findPersons(TestData.PROCESS_CODE, TestData.MAX_NUMBERS_OF_PERSONS);
        List<Person> expected= ...;
        Assertions.assertEquals(expected, result);
        hibernateMockedStatic.verify(() -> Hibernate.initialize(address1), Mockito.times(1));
        hibernateMockedStatic.verify(() -> Hibernate.initialize(address2), Mockito.times(1));
    }
© www.soinside.com 2019 - 2024. All rights reserved.