Menu

  • Home
  • Work
    • Cloud
      • Virtualization
      • IaaS
      • PaaS
    • Java
    • Go
    • C
    • C++
    • JavaScript
    • PHP
    • Python
    • Architecture
    • Others
      • Assembly
      • Ruby
      • Perl
      • Lua
      • Rust
      • XML
      • Network
      • IoT
      • GIS
      • Algorithm
      • AI
      • Math
      • RE
      • Graphic
    • OS
      • Linux
      • Windows
      • Mac OS X
    • BigData
    • Database
      • MySQL
      • Oracle
    • Mobile
      • Android
      • IOS
    • Web
      • HTML
      • CSS
  • Life
    • Cooking
    • Travel
    • Gardening
  • Gallery
  • Video
  • Music
  • Essay
  • Home
  • Work
    • Cloud
      • Virtualization
      • IaaS
      • PaaS
    • Java
    • Go
    • C
    • C++
    • JavaScript
    • PHP
    • Python
    • Architecture
    • Others
      • Assembly
      • Ruby
      • Perl
      • Lua
      • Rust
      • XML
      • Network
      • IoT
      • GIS
      • Algorithm
      • AI
      • Math
      • RE
      • Graphic
    • OS
      • Linux
      • Windows
      • Mac OS X
    • BigData
    • Database
      • MySQL
      • Oracle
    • Mobile
      • Android
      • IOS
    • Web
      • HTML
      • CSS
  • Life
    • Cooking
    • Travel
    • Gardening
  • Gallery
  • Video
  • Music
  • Essay

基于Spring Test和Mockito进行单元测试

8
Sep
2015

基于Spring Test和Mockito进行单元测试

By Alex
/ in Java,Test
/ tags Mock, SpringMVC, 单元测试
5 Comments
场景说明

本文引入一个简单的银行业务场景,用来阐述如何集成Spring Test、Junit、Mockito,以简化单元测试工作。该场景主要的业务代码如下:

Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/**
* 人员
*/
public class Person
{
    private int     id;
    private String  name;
    private Account defaultAccount;
}
/**
* 账户
*/
public class Account
{
    private int  id;
    private int  balance;
    private Person person;
}
/**
* 人员服务接口
*
*/
public interface PersonService
{
    /**
     * 查询人员用户
     */
    Person getPerson( int id );
    /**
    * 得到人员默认账户
    */
    Account getDefaultAccount( Person p );
}
/**
* 账户服务接口
*
*/
public interface AccountService
{
    /**
     * 查询人员默认账户余额
     */
    int queryBalanceOfDefaultAccount( int personId );
}

假设你已经实现了服务AccountService:

AccountServiceImpl.java
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@Service ( "accountService" )
public class AccountServiceImpl implements AccountService
{
    private Map<Integer, Object[]> accountDatabase;
 
    @Inject
    private PersonService          personService;
 
    @PostConstruct
    public void init()
    {
        accountDatabase = new HashMap<Integer, Object[]>();
        //字段:账号,余额
        accountDatabase.put( 100, new Object[] { "6225100", 68861 } );
        accountDatabase.put( 101, new Object[] { "6225101", 1851 } );
        accountDatabase.put( 102, new Object[] { "6225102", 845 } );
        accountDatabase.put( 103, new Object[] { "6225103", 16598 } );
    }
 
    @Override
    public int queryBalanceOfDefaultAccount( int personId )
    {
        Person person = personService.getPerson( personId );
        Account defaultAccount = person.getDefaultAccount();
        return (Integer) accountDatabase.get( defaultAccount.getId() )[1];
    }
 
}

而你的搭档负责的PersonService还没有开发完毕,如何方便的进行单元测试呢?

在JUnit中集成Spring上下文的支持

你可能会觉得,我们不需要在单元测试中引入Spring。对于上面的例子的确可以这么说,它太简单了,AccountServiceImpl 依赖的PersonService完全可以通过setter手工注入。但是实际的开发场景要比这个例子复杂的多,待测试类可能和Spring管理的Beans存在很多关联,它可能依赖于Spring提供的数据源、事务管理器,等等。这些Bean如果都手工管理,将是相当繁琐无味的工作。

使用JUnit 4.x提供的注解 @RunWith ,可以指定单元测试的“运行类”,运行类必须继承自 org.junit.runner.Runner 并实现 run 方法。Spring Test框架提供的运行类是 SpringJUnit4ClassRunner ,使用该类可以轻松的将Spring和JUnit进行集成。该类的用法示例如下:

Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
@RunWith ( SpringJUnit4ClassRunner.class ) //指定单元测试运行类
@ContextConfiguration ( locations = { "applicationContext.xml" } ) //指定Spring配置文件的位置
//很多情况下单元测试离不开事务,下面的注解指明使用的事务管理器
//如果defaultRollback为true,测试运行结束后,默认回滚事务,不影响数据库
@TransactionConfiguration ( transactionManager = "txManager", defaultRollback = true )
@Transactional //指定默认所有测试方法的事务特性
public class AccountServiceTest
{
 
    @Inject
    private SpringManagedBean bean; //任何Spring管理的Bean都可以注入到单元测试类
 
    @BeforeClass
    public static void setUpBeforeClass() throws Exception
    {
    }
    @AfterClass
    public static void tearDownAfterClass() throws Exception
    {
    }
 
    @Before
    public void setUp() throws Exception
    {
    }
 
    @After
    public void tearDown() throws Exception
    {
    }
 
    @Repeat ( 10 )//重复测试10次
    //该测试期望抛出IllegalArgumentException,测试超时1秒
    @Test ( expected = IllegalArgumentException.class, timeout = 1000 )
    @Rollback ( true )
    //测试完毕后回滚
    public void test()
    {
    }
}
AccountService的测试用例

依据上一节的知识,我们编写集成Spring Test的测试用例:

AccountServiceTest.java
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import static org.junit.Assert.*;
@RunWith ( SpringJUnit4ClassRunner.class )
@ContextConfiguration ( locations = { "/applicationContext.xml" } )
public class AccountServiceTest
{
    @Inject
    private AccountService accountService;
 
    @Test
    public void test()
    {
        assertEquals( 68861, accountService.queryBalanceOfDefaultAccount( 100 ) );
    }
}
基于Mockito进行仿冒

引入Spring后,运行单元测试AccountServiceTest,会得到一个NoSuchBeanDefinitionException,这是因为AccountServiceImpl依赖的PersonService没有在Spring中注册。前面我们提到过,PersonService由搭档开发且尚未完成,这个时候要想单独测试AccountServiceImpl,那么就需要开发一个模拟的PersonService。最直接的模拟就是实现PersonService接口,但是不方便、工作量大,因此我们引入Mock框架:Mockito。

本文不去讨论Mockito的API细节,有兴趣的同学可以参考:使用Mockito进行单元测试

可以参考如下方式,单独将Mocketo和JUnit集成:

AccountServiceTest.java
Java
1
2
3
4
5
6
7
8
9
10
@RunWith ( MockitoJUnitRunner.class ) //运行类
public class AccountServiceTest
{
    //AccountService所依赖的其它对象,会使用Mock注入,因此它引用的PersonService将是一个Mock
    @InjectMocks
    private AccountService accountService = new AccountServiceImpl();
    //自动生成一个PersonService的Mock实现
    @Mock
    private PersonService  personService;
}

下面的代码则示例了如何把Spring也集成进来:

AccountServiceTest.java
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@RunWith ( SpringJUnit4ClassRunner.class )
//使用Spring提供的运行类
@ContextConfiguration ( locations = { "/applicationContext.xml" } )
public class AccountServiceTest
{
    @InjectMocks //该字段依赖的其它对象(PersonService),将使用仿冒注入
    @Inject //提示该字段本身由Spring自动注入
    private AccountService accountService;
    @Mock //由Mockito仿冒
    private PersonService  personService;
    @Before
    public void setUp()
    {
        //使得Mockito的注解生效
        MockitoAnnotations.initMocks( this );
    }
    @Test
    public void test()
    {
        //这里断点可以看到accountService.personService的类型是:
        //PersonService$$EnhancerByMockitoWithCGLIB$$61056d67
        //这是Mockito生成的仿冒类
        assertEquals( 68861, accountService.queryBalanceOfDefaultAccount( 100 ) );
    }
}

注意:上面的集成并没有解决AccountServiceImpl对PersonService的依赖性,NoSuchBeanDefinitionException还会出现,除非使用Spring提供的“可选”依赖注入:

AccountServiceImpl.java
Java
1
2
@Autowired ( required = false )
private PersonService          personService;

但这种变通方式改变了应用语义,不应该使用。因此,到目前为止我们只能做到:在单元测试中用仿冒代替一个既有的Bean。

粘合剂:Springockito

Springockito是针对Spring的一个小扩展,它可以简化Mockito仿冒的创建和管理,让Spring与之更无缝的集成:

XHTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8"?>
<beans  xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:mockito="http://www.mockito.org/spring/mockito"
        
        xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.mockito.org/spring/mockito https://cdn.gmem.cc/schema/spring-mockito.xsd
    ">
    <!-- 创建一个受Spring管理的PersonService仿冒,其它Bean很自然的可以获得注入 -->
    <mockito:mock id="personService" class="cc.gmem.study.sam.service.PersonService" />
    <!-- 可以监控(Spying)一个Bean,但不影响它的任何行为,注意beanName必须与@Service指定的名称一致 -->
    <mockito:spy beanName="accountService" />
</beans>

现在可以把PersonService作为一个普通的Spring管理的Bean来看待,下面是最终的测试用例:

AccountServiceTest.java
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Inject
private AccountService accountService;
 
@Inject
private PersonService  personService;  //注入mock,就像注入普通Bean一样
 
@Test
public void test()
{
    int id = 0;
    Person alex = new Person( id, "Alex", new Account( 100 ) );
    //对作为Bean的Mock进行打桩,设定后续方法调用的行为,就像为普通Mock打桩一样
    when( personService.getPerson( 0 ) ).thenReturn( alex );
    //验证结果
    assertEquals( 68861, accountService.queryBalanceOfDefaultAccount( id ) );
 
    //验证queryBalanceOfDefaultAccount方法被调用了一次
    verify( accountService ).queryBalanceOfDefaultAccount( id );
    //Mockito要求verify的入参必须是Mock,Springockito解除了这一限制
}

我们使用了PersonService的Mock,而不要求它已经被实现、注册到Spring; 同时,我们可以对既有的Bean进行监控,而不要求它是一个Mock。

 Springockito也提供了与XML配置等价的注解方式:

AccountServiceTest.java
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
@RunWith ( SpringJUnit4ClassRunner.class )
//注意:必须修改loader为SpringockitoContextLoader.class
@ContextConfiguration ( loader = SpringockitoContextLoader.class, locations = { "/applicationContext.xml" } )
public class AccountServiceTest
{
    @WrapWithSpy  //mockito:spy
    @Inject
    private AccountService accountService;
    
    @ReplaceWithMock ( beanName = "personService" ) //mockito:mock
    @Inject
    private PersonService  personService;
}
Spring MVC的测试

Spring 3.2的Test子项目提供了类MockMvc,调用其 perform() 方法,可以触发一次“请求”,该调用会返回一个 ResultActions 接口。可以针对ResultActions执行一系列的动作和断言,或者返回处理结果 MvcResult ,该接口提供以下方法:

 方法 说明 
andExpect(ResultMatcher) 执行期望(断言),一般会配合静态导入:MockMvcRequestBuilders.*、MockMvcResultMatchers.*使用。举例:
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
mockMvc.perform( get( "/person/1" ) )
//期望HTTP状态码为200
.andExpect( status.isOk() )
//期望响应的MIME类型为JSON
.andExpect( content().mimeType( MediaType.APPLICATION_JSON ) )
//期望响应中的JsonPath对应的值
//JsonPath类似于XPath,可参:http://goessner.net/articles/JsonPath/
.andExpect( jsonPath( "$.person.name" ).equalTo( "Alex" ) );
 
mockMvc.perform( post( "/form" ) )
//期望请求被重定向到URL
.andExpect( redirectedUrl( "/person/1" ) )
//期望模型属性的数量
.andExpect( model().size( 1 ) )
//期望模型属性的存在性
.andExpect( model().attributeExists( "person" ) );
 
//模拟请求参数、请求体
mockMvc.perform(
    post( "/form" )
        .param( "name", "Alex" )
        .param( "id", "0" )
        .param( "defacc", "100" )
        .content( "{}" ) //设置请求体,UTF-8字符串
);
andDo(ResultHandler)  执行一个动作,一般会配合静态导入:MockMvcResultHandlers.*。举例:
Java
1
mockMvc.perform( get( "/form" ) ).andDo( print() );
MvcResult andReturn() 得到Mvc处理结果,从中可以HttpServletRequest、HttpServletResponse、MVC处理器、处理器抛出的异常、HandlerInterceptor、ModelAndView等内容
AccountController及其测试用例

我们开发一个简单的Controller类,它能够接收查询默认账户余额的请求,并返回一个包含人员、余额信息的映射:

AccountController.java
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Controller ( "accountController" )
@RequestMapping ( "/account" )
public class AccountController
{
    @Inject
    private AccountService accountService;
 
    @RequestMapping ( "/{personId}/defacct/balance" )
    @ResponseBody
    public Map<String, Integer> queryBalanceOfDefaultAccount( @PathVariable int personId, @RequestParam long timestamp )
    {
        int balance = accountService.queryBalanceOfDefaultAccount( personId );
        Map<String, Integer> ret = new LinkedHashMap<String, Integer>();
        ret.put( "personId", personId );
        ret.put( "balance", balance );
        return ret;
    }
}

假设我们的客户端需要JSON格式的数据,我们可以利用MockMvc来模拟客户端并验证。下面是一个简单的示例(包含JUnit测试类和Spring配置文件):

applicationContext.xml
XHTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="UTF-8"?>
<beans  xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:mockito="http://www.mockito.org/spring/mockito"
        
        xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.mockito.org/spring/mockito https://cdn.gmem.cc/schema/spring-mockito.xsd
    ">
    <context:annotation-config />
    
    <!-- 该接口尚未实现,必须仿冒 -->
    <mockito:mock id="personService" class="cc.gmem.study.sam.service.PersonService" />
    
    <!-- 该接口虽已实现,但是为了隔离依赖单独测试MVC部分,我们这里使用仿冒 -->
    <mockito:mock id="accountService" class="cc.gmem.study.sam.service.AccountService" />
</beans>

applicationContext-mvc.xml
XHTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mockito="http://www.mockito.org/spring/mockito"
      
       xsi:schemaLocation="
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
        http://www.mockito.org/spring/mockito https://cdn.gmem.cc/schema/spring-mockito.xsd
        
    ">
    <!-- 我们需要监控此Bean被调用的情况 -->
    <mockito:spy beanName="accountController" />
    <context:component-scan base-package="cc.gmem.study.sam.ctrl" />
 
    <mvc:annotation-driven />
    <bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
        <property name="order" value="0" />
    </bean>
</beans>

AccountControllerTest.java
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import static org.springframework.http.MediaType.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
 
@RunWith ( SpringJUnit4ClassRunner.class )
//提示该测试使用WebApplicationContext,需要3.2版本
//该注解的value用来说明不带Spring前缀的Resource(例如classpath:)的寻找路径
@WebAppConfiguration ( "src/main/webapp" )
//定义WebApplicationContext的层次,需要3.2.2版本
@ContextHierarchy ( {
        //这里目前不能使用load:SpringockitoContextLoader,可能Springockito注解尚不兼容3.2.2
        //因此我们使用XML方式配置Springockito
        //父上下文
        @ContextConfiguration ( locations = "classpath:applicationContext.xml" ),
        //子上下文
        @ContextConfiguration ( locations = "classpath:applicationContext-mvc.xml" )
} )
public class AccountControllerTest
{
    private MockMvc               mockMvc; //需要3.2版本
    
    @Inject
    private WebApplicationContext wac; //最低层次的上下文被注入
    
    @Inject
    private AccountController accountController; //被测试类
    
    @Inject
    private AccountService accountService;
    
    @Before
    public void setUp() throws Exception
    {
        //初始化MockMvc
        mockMvc = MockMvcBuilders.webAppContextSetup( wac ).build();
    }
 
    @Test
    public void test() throws Exception
    {
        int personId = 0;
        int balance = 1000;
        long timestamp = System.currentTimeMillis();
        
        /*仿冒打桩*/
        when(accountService.queryBalanceOfDefaultAccount( personId )).thenReturn( balance);
        
        /*HTTP请求模拟以及结果验证*/
        mockMvc.perform(
                get( "/account/{personId}/defacct/balance", personId )
                .accept( APPLICATION_JSON ) //请求返回JSON格式的响应
                //设置请求头
                .header( "JSESSIONID", new Object[]{"aue60a2p2m8fe5s0t2m1am78t4"} )
                //设置请求参数
                .param( "timestamp", String.valueOf( timestamp ) )
        )
        .andExpect( status().isOk() )
        .andExpect( content().contentTypeCompatibleWith( APPLICATION_JSON ) ) //期望返回JSON格式的响应
        .andExpect( jsonPath( "$.balance" ).value( balance ) ) //JSONPath验证
        .andDo( print() ); //打印请求、响应和处理过程的详细信息,以便核查
        
        /*Mockito验证*/
        //验证accountController恰好被调用了一次
        verify( accountController ).queryBalanceOfDefaultAccount( personId, timestamp );
        //验证AccountService至少被调用了一次
        verify( accountService,atLeast( 1 ) ).queryBalanceOfDefaultAccount( personId );
        
        /*Junit验证*/
        assertTrue( true );
    }
}

可以看到,我们在测试用例中基于MockMvc提供的丰富API,来构建仿冒的请求,并验证Spring MVC的响应。同时,我们使用Mockito来隔离AccountService服务,简化了依赖管理。 

附录

本文使用的Maven POM依赖配置如下:

pom.xml
XHTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
<dependencies>
    <dependency>
        <groupId>javax.annotation</groupId>
        <artifactId>jsr250-api</artifactId>
        <version>1.0</version>
    </dependency>
    <dependency>
        <groupId>javax.inject</groupId>
        <artifactId>javax.inject</artifactId>
        <version>1</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>2.4</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>jsp-api</artifactId>
        <version>2.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>
    <dependency>
        <groupId>taglibs</groupId>
        <artifactId>standard</artifactId>
        <version>1.1.2</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax.el</groupId>
        <artifactId>el-api</artifactId>
        <version>2.2</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>3.2.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>3.2.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>3.2.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-orm</artifactId>
        <version>3.2.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>3.2.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.0.4</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.0.4</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-annotations</artifactId>
        <version>2.0.4</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.15</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.6.1</version>
    </dependency>
 
 
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>3.2.3.RELEASE</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-all</artifactId>
        <version>1.9.0</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.kubek2k</groupId>
        <artifactId>springockito</artifactId>
        <version>1.0.9</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.kubek2k</groupId>
        <artifactId>springockito-annotations</artifactId>
        <version>1.0.9</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.jayway.jsonpath</groupId>
        <artifactId>json-path-assert</artifactId>
        <version>0.9.1</version>
        <scope>test</scope>
    </dependency>
</dependencies>
← KVM和QEMU学习笔记
snmp4j学习笔记 →
5 Comments On This Topic
  1. 回复
    Franck
    2017/04/28

    写得非常好,很详尽。给我很大的帮助! 十分感谢!

    • 回复
      Alex
      2017/05/02

      客气了~~共同进步

    • 回复
      skyy
      2017/10/19

      @ReplaceWithMock ( beanName = "personService" ) //mockito:mock
      @Inject
      private PersonService personService;

      请问楼主,这个不报错么? personService 没在xml 定义也没有实现类用 service 注解的情况下?我这边直接就报错不编译了

      • 回复
        Alex
        2017/10/19

        刚试了一下,以下代码不报错:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        @RunWith( SpringJUnit4ClassRunner.class )
        @Configuration
        // 请把空白Spring配置文件AccountServiceImplTest-context.xml放在同目录下
        @ContextConfiguration( loader = SpringockitoContextLoader.class )
        public class AccountServiceImplTest {
         
            @ReplaceWithMock
            @Inject
            private PersonService service;
         
            @Test
            public void testDeposit() {
                System.out.println();
            }
        }

        但是我使用IntelliJ IDEA作为开发工具,此工具的Inspection功能会报Could not autowire. No beans of 'PersonService' type found。这个对运行没有影响。

        另外,Springockito目前不怎么维护了。建议使用Spring Boot,可以零XML配置的注入Mock到单元测试用例,可以参考:
        https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications-mocking-beans

        • 回复
          skyy
          2017/10/19

          谢了,我之前是把这个@RunWith( SpringJUnit4ClassRunner.class )加在测试类的父类上了,加在测试类上就行了

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

Related Posts

  • 使用Mockito进行单元测试
  • Go语言单元测试和仿冒
  • Python单元测试
  • Ginkgo学习笔记
  • 使用log4jdbc记录SQL语句的执行情况

Recent Posts

  • Investigating and Solving the Issue of Failed Certificate Request with ZeroSSL and Cert-Manager
  • A Comprehensive Study of Kotlin for Java Developers
  • 背诵营笔记
  • 利用LangChain和语言模型交互
  • 享学营笔记
ABOUT ME

汪震 | Alex Wong

江苏淮安人,现居北京。目前供职于腾讯云,专注容器方向。

GitHub:gmemcc

Git:git.gmem.cc

Email:gmemjunk@gmem.cc@me.com

ABOUT GMEM

绿色记忆是我的个人网站,域名gmem.cc中G是Green的简写,MEM是Memory的简写,CC则是我的小天使彩彩名字的简写。

我在这里记录自己的工作与生活,同时和大家分享一些编程方面的知识。

GMEM HISTORY
v2.00:微风
v1.03:单车旅行
v1.02:夏日版
v1.01:未完成
v0.10:彩虹天堂
v0.01:阳光海岸
MIRROR INFO
Meta
  • Log in
  • Entries RSS
  • Comments RSS
  • WordPress.org
Recent Posts
  • Investigating and Solving the Issue of Failed Certificate Request with ZeroSSL and Cert-Manager
    In this blog post, I will walk ...
  • A Comprehensive Study of Kotlin for Java Developers
    Introduction Purpose of the Study Understanding the Mo ...
  • 背诵营笔记
    Day 1 Find Your Greatness 原文 Greatness. It’s just ...
  • 利用LangChain和语言模型交互
    LangChain是什么 从名字上可以看出来,LangChain可以用来构建自然语言处理能力的链条。它是一个库 ...
  • 享学营笔记
    Unit 1 At home Lesson 1 In the ...
  • K8S集群跨云迁移
    要将K8S集群从一个云服务商迁移到另外一个,需要解决以下问题: 各种K8S资源的迁移 工作负载所挂载的数 ...
  • Terraform快速参考
    简介 Terraform用于实现基础设施即代码(infrastructure as code)—— 通过代码( ...
  • 草缸2021
    经过四个多月的努力,我的小小荷兰景到达极致了状态。

  • 编写Kubernetes风格的APIServer
    背景 前段时间接到一个需求做一个工具,工具将在K8S中运行。需求很适合用控制器模式实现,很自然的就基于kube ...
  • 记录一次KeyDB缓慢的定位过程
    环境说明 运行环境 这个问题出现在一套搭建在虚拟机上的Kubernetes 1.18集群上。集群有三个节点: ...
  • eBPF学习笔记
    简介 BPF,即Berkeley Packet Filter,是一个古老的网络封包过滤机制。它允许从用户空间注 ...
  • IPVS模式下ClusterIP泄露宿主机端口的问题
    问题 在一个启用了IPVS模式kube-proxy的K8S集群中,运行着一个Docker Registry服务 ...
  • 念爷爷
      今天是爷爷的头七,十二月七日、阴历十月廿三中午,老人家与世长辞。   九月初,回家看望刚动完手术的爸爸,发

  • 6 杨梅坑

  • liuhuashan
    深圳人才公园的网红景点 —— 流花山

  • 1 2020年10月拈花湾

  • 内核缺陷触发的NodePort服务63秒延迟问题
    现象 我们有一个新创建的TKE 1.3.0集群,使用基于Galaxy + Flannel(VXLAN模式)的容 ...
  • Galaxy学习笔记
    简介 Galaxy是TKEStack的一个网络组件,支持为TKE集群提供Overlay/Underlay容器网 ...
TOPLINKS
  • Zitahli's blue 91 people like this
  • 梦中的婚礼 64 people like this
  • 汪静好 61 people like this
  • 那年我一岁 36 people like this
  • 为了爱 28 people like this
  • 小绿彩 26 people like this
  • 杨梅坑 6 people like this
  • 亚龙湾之旅 1 people like this
  • 汪昌博 people like this
  • 彩虹姐姐的笑脸 24 people like this
  • 2013年11月香山 10 people like this
  • 2013年7月秦皇岛 6 people like this
  • 2013年6月蓟县盘山 5 people like this
  • 2013年2月梅花山 2 people like this
  • 2013年淮阴自贡迎春灯会 3 people like this
  • 2012年镇江金山游 1 people like this
  • 2012年徽杭古道 9 people like this
  • 2011年清明节后扬州行 1 people like this
  • 2008年十一云龙公园 5 people like this
  • 2008年之秋忆 7 people like this
  • 老照片 13 people like this
  • 火一样的六月 16 people like this
  • 发黄的相片 3 people like this
  • Cesium学习笔记 90 people like this
  • IntelliJ IDEA知识集锦 59 people like this
  • 基于Kurento搭建WebRTC服务器 38 people like this
  • Bazel学习笔记 37 people like this
  • PhoneGap学习笔记 32 people like this
  • NaCl学习笔记 32 people like this
  • 使用Oracle Java Mission Control监控JVM运行状态 29 people like this
  • 基于Calico的CNI 27 people like this
  • Ceph学习笔记 27 people like this
  • Three.js学习笔记 24 people like this
Tag Cloud
ActiveMQ AspectJ CDT Ceph Chrome CNI Command Cordova Coroutine CXF Cygwin DNS Docker eBPF Eclipse ExtJS F7 FAQ Groovy Hibernate HTTP IntelliJ IO编程 IPVS JacksonJSON JMS JSON JVM K8S kernel LB libvirt Linux知识 Linux编程 LOG Maven MinGW Mock Monitoring Multimedia MVC MySQL netfs Netty Nginx NIO Node.js NoSQL Oracle PDT PHP Redis RPC Scheduler ServiceMesh SNMP Spring SSL svn Tomcat TSDB Ubuntu WebGL WebRTC WebService WebSocket wxWidgets XDebug XML XPath XRM ZooKeeper 亚龙湾 单元测试 学习笔记 实时处理 并发编程 彩姐 性能剖析 性能调优 文本处理 新特性 架构模式 系统编程 网络编程 视频监控 设计模式 远程调试 配置文件 齐塔莉
Recent Comments
  • qg on Istio中的透明代理问题
  • heao on 基于本地gRPC的Go插件系统
  • 黄豆豆 on Ginkgo学习笔记
  • cloud on OpenStack学习笔记
  • 5dragoncon on Cilium学习笔记
  • Archeb on 重温iptables
  • C/C++编程:WebSocketpp(Linux + Clion + boostAsio) – 源码巴士 on 基于C/C++的WebSocket库
  • jerbin on eBPF学习笔记
  • point on Istio中的透明代理问题
  • G on Istio中的透明代理问题
  • 绿色记忆:Go语言单元测试和仿冒 on Ginkgo学习笔记
  • point on Istio中的透明代理问题
  • 【Maven】maven插件开发实战 – IT汇 on Maven插件开发
  • chenlx on eBPF学习笔记
  • Alex on eBPF学习笔记
  • CFC4N on eBPF学习笔记
  • 李运田 on 念爷爷
  • yongman on 记录一次KeyDB缓慢的定位过程
  • Alex on Istio中的透明代理问题
  • will on Istio中的透明代理问题
  • will on Istio中的透明代理问题
  • haolipeng on 基于本地gRPC的Go插件系统
  • 吴杰 on 基于C/C++的WebSocket库
©2005-2025 Gmem.cc | Powered by WordPress | 京ICP备18007345号-2