使用Mockito模拟自动依赖关系

发布于 2025-01-25 12:31:19 字数 1428 浏览 5 评论 0原文

我正在用Junit 5和Mockito 4编写一个春季项目的单元测试。

我必须测试一个通过构造器和其他2个对象通过@Autowired进行2个对象的类。我需要模拟这4个对象,因此我在测试类中用@mock注释了它们,然后用@InjectMocks注释了经过测试的类。

我以为@InjectMocks会将我的4个模拟注入MyService,但它只是注入由构造函数传递的2个模拟,而其他2则是无效的。

我正在寻找一种解决方案,这并不意味着已测试服务的变化。

经过测试的班级看起来像这样:

@Service
public class MyService {

private String key = "KEY";

@Autowired
private FirstApiWrapper firstApiWrapper;

@Autowired
private SecondApiWrapper secondApiWrapper;

private MyRepository myRepository;

private OtherService otherService;

@Autowired
public MyService(
    MyRepository myRepository,
    OtherService otherService
) {
    super();
    this.myRepository = myRepository;
    this.otherService = otherService;
}

我的测试类看起来像:

@ExtendWith(MockitoExtension.class)
public class MyServiceTest {

@Mock
MyRepository myRepository;

@Mock
OtherService otherService;

@Mock
FirstApiWrapper firstApiWrapper;

@Mock
SecondApiWrapper secondApiWrapper;

@InjectMocks
MyService myService;

关于我的代码有什么问题的想法? 非常感谢!

- 我还尝试了一些基于

@Mock
FirstApiWrapper firstApiWrapper;
@Mock
SecondApiWrapper secondApiWrapper;
@InjectMocks
MyService myService;

@BeforeEach
private void setUp() {

    myService = new MyService(
            Mockito.mock(MyRepository.class),
            Mockito.mock(OtherService.class)
    );
}

但是结果完全相同。另外,如果我删除存储库和服务实例并尝试仅注入包装器,它仍然会失败!

I'm writing unit tests for a Spring project with Junit 5 and Mockito 4.

I have to test a class that takes 2 objects via constructor and other 2 via @Autowired. I need to mock those 4 objects, so I annotated them with @Mock in my test class and then annotated the tested class with @InjectMocks.

I thought that @InjectMocks would inject my 4 mocks into myService, but it's only injecting the 2 that are passed by constructor, while the other 2 are null.

I'm looking for a solution that doesn't implies changes in the tested service.

The tested class looks like this:

@Service
public class MyService {

private String key = "KEY";

@Autowired
private FirstApiWrapper firstApiWrapper;

@Autowired
private SecondApiWrapper secondApiWrapper;

private MyRepository myRepository;

private OtherService otherService;

@Autowired
public MyService(
    MyRepository myRepository,
    OtherService otherService
) {
    super();
    this.myRepository = myRepository;
    this.otherService = otherService;
}

My test class looks like this:

@ExtendWith(MockitoExtension.class)
public class MyServiceTest {

@Mock
MyRepository myRepository;

@Mock
OtherService otherService;

@Mock
FirstApiWrapper firstApiWrapper;

@Mock
SecondApiWrapper secondApiWrapper;

@InjectMocks
MyService myService;

Any ideas of what is wrong with my code?
Thank you all very much!

-- I've also tried something based on this question:

@Mock
FirstApiWrapper firstApiWrapper;
@Mock
SecondApiWrapper secondApiWrapper;
@InjectMocks
MyService myService;

@BeforeEach
private void setUp() {

    myService = new MyService(
            Mockito.mock(MyRepository.class),
            Mockito.mock(OtherService.class)
    );
}

But the result is exactly the same. Also, if I delete repository and service instances and try to inject only the wrappers, It still fails!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

挽袖吟 2025-02-01 12:31:19

我通过将其添加到测试类中,找到了一种解决现有代码而无需重写现有代码的方法:

@BeforeEach
private void setUp() {
    MockitoAnnotations.openMocks(this);
}

但是我不确定它是否是“正确”的方法。

I found a way to solve it without rewriting the existing code, by adding this to the test class:

@BeforeEach
private void setUp() {
    MockitoAnnotations.openMocks(this);
}

But I'm not sure if it is a "correct" way of doing it.

蓝海似她心 2025-02-01 12:31:19

一旦自动引起的字段问题是Mockito将无法注入任何东西。那么,如果您已经进行了构造函数注入,为什么还需要混合注入风格呢?

重写类:

@Service
public class MyService {

private String key = "KEY";

private final MyRepository myRepository;

private final OtherService otherService;

private final FirstApiWrapper firstApiWrapper;

private final SecondApiWrapper secondApiWrapper;

@Autowired // if its the only constructor in the class, you can omit @Autowired, spring will be able to call it anyway. You can even use Lombok to generate this constructor for, so you won't need to even write this method
public MyService(
    MyRepository myRepository,
    OtherService otherService,
    FirstApiWrapper firstApiWrapper,
    SecondApiWrapper secondApiWrapper

) {

    this.myRepository = myRepository;
    this.otherService = otherService;
    this.firstApiWrapper = firstApiWrapper;
    this.secondApiWrapper = secondApiWrapper;
}

使用此设计,您可以安全地使用@mock/@injectMocks测试中的注释
Mockito将创建类的实例,并注入相关的模拟。

Once of the issues with fields autowiring is that mockito won't be able to inject anything. So why do you need to mix the styles of injection if you already have a constructor-injection?

Rewrite your class:

@Service
public class MyService {

private String key = "KEY";

private final MyRepository myRepository;

private final OtherService otherService;

private final FirstApiWrapper firstApiWrapper;

private final SecondApiWrapper secondApiWrapper;

@Autowired // if its the only constructor in the class, you can omit @Autowired, spring will be able to call it anyway. You can even use Lombok to generate this constructor for, so you won't need to even write this method
public MyService(
    MyRepository myRepository,
    OtherService otherService,
    FirstApiWrapper firstApiWrapper,
    SecondApiWrapper secondApiWrapper

) {

    this.myRepository = myRepository;
    this.otherService = otherService;
    this.firstApiWrapper = firstApiWrapper;
    this.secondApiWrapper = secondApiWrapper;
}

With this design you can safely use @Mock / @InjectMocks annotations in the test
Mockito will create the instance of the class and inject relevant mocks.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文