且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Mockito,JUnit和Spring

更新时间:2023-09-17 12:12:10

老实说我不是确定我是否真的理解你的问题:PI将尽可能地从原始问题中得到澄清:

Honestly I am not sure if I really understand your question :P I will try to clarify as much as I can, from what I get from your original question:

首先,在大多数情况下,你对Spring不应该有任何顾虑。你很少需要参与编写单元测试。在正常情况下,您只需要在单元测试中实例化被测系统(SUT,要测试的目标),并在测试中注入SUT的依赖关系。依赖关系通常是模拟/存根。

First, in most case, you should NOT have any concern on Spring. You rarely need to have spring involved in writing your unit test. In normal case, you only need to instantiate the system under test (SUT, the target to be tested) in your unit test, and inject dependencies of SUT in the test too. The dependencies are usually a mock/stub.

您的原始建议方式,示例2,3正是我上面所描述的。

Your original suggested way, and example 2, 3 is precisely doing what I am describing above.

在极少数情况下(例如,集成测试或某些特殊单元测试),您需要创建一个Spring应用程序上下文,并从应用程序上下文中获取您的SUT。在这种情况下,我相信你可以:

In some rare case (like, integration tests, or some special unit tests), you need to create a Spring app context, and get your SUT from the app context. In such case, I believe you can:

1)在spring app ctx中创建你的SUT,得到它的引用,然后注入模拟

1) Create your SUT in spring app ctx, get reference to it, and inject mocks to it

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("test-app-ctx.xml")
public class FooTest {

    @Autowired
    @InjectMocks
    TestTarget sut;

    @Mock
    Foo mockFoo;

    @Before
    /* Initialized mocks */
    public void setup() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void someTest() {
         // ....
    }
}

2)按照链接中描述的方式 Spring集成测试,创建模拟对象。这种方法是在Spring的应用程序上下文中创建模拟,你可以从app ctx获取模拟对象来进行存根/验证:

2) follow the way described in your link Spring Integration Tests, Creating Mock Objects. This approach is to create mocks in Spring's app context, and you can get the mock object from the app ctx to do your stubbing/verification:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("test-app-ctx.xml")
public class FooTest {

    @Autowired
    TestTarget sut;

    @Autowired
    Foo mockFoo;

    @Test
    public void someTest() {
         // ....
    }
}

两种方式都应该有效。主要区别在于前一种情况将在经历spring的生命周期等之后注入依赖项(例如bean初始化),而后一种情况在beforehands之前注入。例如,如果您的SUT实现了spring的InitializingBean,并且初始化例程涉及依赖项,您将看到这两种方法之间的区别。我相信这两种方法没有对错,只要你知道你在做什么。

Both ways should work. The main difference is the former case will have the dependencies injected after going through spring's lifecycle etc. (e.g. bean initialization), while the latter case is injected beforehands. For example, if your SUT implements spring's InitializingBean, and the initialization routine involves the dependencies, you will see the difference between these two approach. I believe there is no right or wrong for these 2 approaches, as long as you know what you are doing.

只是补充,@ Mock,@ Inject,MocktoJunitRunner等使用Mockito都是不必要的。它们只是用来保存你输入Mockito.mock(Foo.class)和一堆setter调用的工具。

Just a supplement, @Mock, @Inject, MocktoJunitRunner etc are all unnecessary in using Mockito. They are just utilities to save you typing the Mockito.mock(Foo.class) and bunch of setter invocations.