- 浏览: 1225598 次
- 性别:
- 来自: 广州
文章分类
- 全部博客 (353)
- java基础 (40)
- tapestry (16)
- gwt (14)
- ajax (7)
- linux (8)
- ubuntu (18)
- eclipse (6)
- dojo (2)
- javascript (7)
- maven (4)
- 日常生活 (29)
- web2.0 (2)
- jsonrpc (1)
- compass (1)
- lucene (0)
- spring (10)
- cluster (3)
- 数据结构 (2)
- sqlserver (1)
- tomcat (2)
- swing (1)
- servlet (1)
- hibernate (1)
- firefox (1)
- Java-Puzzlers (1)
- Wicket (2)
- mysql (10)
- windows (5)
- Webwork (1)
- struts2 (1)
- Seam (2)
- jboss (1)
- idea (6)
- 分布计算 (3)
- Python-Django (7)
- Hadoop (1)
- 工具 (3)
- Tokyo Tyrant (2)
- Comet (1)
- android (115)
- 音乐 (6)
- cxf (1)
- mqtt (1)
最新评论
-
hesai_vip:
学习了,感谢
gradlew wrapper使用下载到本地的gradle.zip文件安装。 -
imknown:
姚瑶大坏蛋 写道我也遇到了这个,用你这个方法,导致下拉刷新不起 ...
解决android-Ultra-Pull-To-Refresh下拉刷新组件中嵌套ViewPager的一个bug -
姚瑶大坏蛋:
我也遇到了这个,用你这个方法,导致下拉刷新不起作用了,你遇到过 ...
解决android-Ultra-Pull-To-Refresh下拉刷新组件中嵌套ViewPager的一个bug -
寐语者:
LeaderElection(String zookeeper ...
使用Zookeeper来为你的程序加上Leader Election的功能。 -
fyc0109:
博主, 安装了一部分还是报这个错误!FAILURE: Buil ...
gradlew wrapper使用下载到本地的gradle.zip文件安装。
使用Spring AbstractTransactionalDataSourceSpringContextTests测试
- 博客分类:
- spring
在使用AbstractTransactionalDataSourceSpringContextTests这个作为测试hibernate的Service时,遇到这样的一个问题。 就是一定要在代码中显示的调用session.flush()。 更改操作才能立即看到。。
比如
如果我不在getBillingEntityService().deleteBillingEntity(1) 方法里面调用sesson.flush()的话。 这个测试是失败的。但是在真是环境中的话不调用session.flush()是能行的。Hibernate 默认的是autoFlush 大家应该也遇到相同的问题吧。 是如何解决的?
谢谢
看看你mysql数据库是什么类型的。 ISM类型的应该不能回滚,因为不支持事务。 换成innodb
hibernate delete只是在缓存中将某个持久对象给标记成删除的,但没有flunsh就实际没有执行删除操作,而JdbcTemplate不在session控制之下,因此还能从数据库找到标记为删除的记录。当然,被标记为删除的记录,再次通过hibernate来查找就会抛出异常,说已经被删除了。
如果用了hibernate
测试的时候用hsqldb就可以了
这段代码的本意就是判断session中的对象是否被删除了。
前头漏了段
我不认为测试一定要直接操作数据库,尤其是用hibernate的时候。
我觉得改变测试方法比较好:
刚刚又想到了你这样会不会有问题。看下面的代码,我把delete变成了save
因为在testSave中是在一个session中, 所以service.get的话可能根本不会读数据库里面的值, 而是拿的session cache中的?
这个问题我看错了,原来问题是jdbctemplate.execute(),不是不同session的问题。
只能显示调用sessionFlush了,hibernateTemplate和jdbcTemplate一块用,这样不一致性的问题就会一直存在。
是的 我没有发现,hibernateTemplate有executeWithSession这个方法。
正规的话 当然是应该用jdbc来测试的。
这个问题我看错了,原来问题是jdbctemplate.execute(),不是不同session的问题。
只能显示调用sessionFlush了,hibernateTemplate和jdbcTemplate一块用,这样不一致性的问题就会一直存在。
但是不知道为什么用不同的session flush一下也会起作用?
flush后session是与数据库同步的,因为测试不是多线程,session之间就不会出现不一致的情况。
我觉得改变测试方法比较好:
我有遇到你这种情况, 一个同事使用jdbc去验证的时候 会有问题, 但是我用service去拿的话 就能通过。 最后发现我这里发送了update语句,而用jdbc去验证的话并没有flush。 我不觉得你上面的方式好。 因为我这种方式对于使用jdbc或者其他方式去验证都是有效的, 而且如果我没有get find方法呢? 我还要为测试去加多这样的方法?
我觉得改变测试方法比较好:
这样说就能够解释了,我一直以为session在dao.delete()方法结束后就关闭了。哈哈
比如
public void testDeleteBillingEntity(){ getBillingEntityService().deleteBillingEntity(1); assertEquals("BillingEntity(1) should be not existed", getJdbcTemplate().queryForInt("SELECT COUNT(*) FROM BILLING_ENTITY WHERE ID=1"), 0); }
如果我不在getBillingEntityService().deleteBillingEntity(1) 方法里面调用sesson.flush()的话。 这个测试是失败的。但是在真是环境中的话不调用session.flush()是能行的。Hibernate 默认的是autoFlush 大家应该也遇到相同的问题吧。 是如何解决的?
谢谢
评论
29 楼
dengyin2000
2007-05-15
zhour560 写道
我也遇到Spring AbstractTransactionalDataSourceSpringContextTests测试不可以回滚的问题。数据库是MYSQL。在测试里面新增记录的时候,竟然加数据库里面去了。而且更新和删除都可以回滚的!
public abstract class SpringTestCaseBase extends AbstractTransactionalDataSourceSpringContextTests {
protected SimpleDateFormat sdf;
public SpringTestCaseBase() {
// query the protected variables to implement denpendency injection automatically,
// so we don't need to write settor and gettor methods anymore.
this.setPopulateProtectedVariables(true);
sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.setTimeZone(TimeZone.getDefault());
}
protected String[] getConfigLocations() {
return new String[] { "file:web/WEB-INF/applicationContext*.xml",
"file:web/WEB-INF/test-ApplicationContext*.xml"};
}
protected void flushSession(){
SessionFactory sessionFactory = (SessionFactory)applicationContext.getBean("sessionFactory");
sessionFactory.getCurrentSession().flush();
}
}
这是我测试基类。
public abstract class SpringTestCaseBase extends AbstractTransactionalDataSourceSpringContextTests {
protected SimpleDateFormat sdf;
public SpringTestCaseBase() {
// query the protected variables to implement denpendency injection automatically,
// so we don't need to write settor and gettor methods anymore.
this.setPopulateProtectedVariables(true);
sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.setTimeZone(TimeZone.getDefault());
}
protected String[] getConfigLocations() {
return new String[] { "file:web/WEB-INF/applicationContext*.xml",
"file:web/WEB-INF/test-ApplicationContext*.xml"};
}
protected void flushSession(){
SessionFactory sessionFactory = (SessionFactory)applicationContext.getBean("sessionFactory");
sessionFactory.getCurrentSession().flush();
}
}
这是我测试基类。
看看你mysql数据库是什么类型的。 ISM类型的应该不能回滚,因为不支持事务。 换成innodb
28 楼
zhour560
2007-05-15
我也遇到Spring AbstractTransactionalDataSourceSpringContextTests测试不可以回滚的问题。数据库是MYSQL。在测试里面新增记录的时候,竟然加数据库里面去了。而且更新和删除都可以回滚的!
public abstract class SpringTestCaseBase extends AbstractTransactionalDataSourceSpringContextTests {
protected SimpleDateFormat sdf;
public SpringTestCaseBase() {
// query the protected variables to implement denpendency injection automatically,
// so we don't need to write settor and gettor methods anymore.
this.setPopulateProtectedVariables(true);
sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.setTimeZone(TimeZone.getDefault());
}
protected String[] getConfigLocations() {
return new String[] { "file:web/WEB-INF/applicationContext*.xml",
"file:web/WEB-INF/test-ApplicationContext*.xml"};
}
protected void flushSession(){
SessionFactory sessionFactory = (SessionFactory)applicationContext.getBean("sessionFactory");
sessionFactory.getCurrentSession().flush();
}
}
这是我测试基类。
public abstract class SpringTestCaseBase extends AbstractTransactionalDataSourceSpringContextTests {
protected SimpleDateFormat sdf;
public SpringTestCaseBase() {
// query the protected variables to implement denpendency injection automatically,
// so we don't need to write settor and gettor methods anymore.
this.setPopulateProtectedVariables(true);
sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.setTimeZone(TimeZone.getDefault());
}
protected String[] getConfigLocations() {
return new String[] { "file:web/WEB-INF/applicationContext*.xml",
"file:web/WEB-INF/test-ApplicationContext*.xml"};
}
protected void flushSession(){
SessionFactory sessionFactory = (SessionFactory)applicationContext.getBean("sessionFactory");
sessionFactory.getCurrentSession().flush();
}
}
这是我测试基类。
27 楼
dengyin2000
2007-05-11
用session.get试试
26 楼
晨星★~雨泪
2007-05-11
我总觉得既然已删除 那么查出的结果应为NULL 才对,为什么要报错?
如果我 用 Hibernate findByid 去查一个数据表里没有的记录 那不是老抛异常.
如果我 用 Hibernate findByid 去查一个数据表里没有的记录 那不是老抛异常.
25 楼
spiritfrog
2007-05-10
晨星★~雨泪 写道
我用 Hibernate delete 后 用Spring JdbcTemplate 查被删的记录还是存在,可用 Hibernate findByid 就会报 该记录已删 的错误.郁闷
hibernate delete只是在缓存中将某个持久对象给标记成删除的,但没有flunsh就实际没有执行删除操作,而JdbcTemplate不在session控制之下,因此还能从数据库找到标记为删除的记录。当然,被标记为删除的记录,再次通过hibernate来查找就会抛出异常,说已经被删除了。
24 楼
spiritfrog
2007-05-10
这里是需要调用session的flunsh的,因为getJdbcTemplate().queryForInt方法不会flunsh缓存。
23 楼
晨星★~雨泪
2007-05-10
我用 Hibernate delete 后 用Spring JdbcTemplate 查被删的记录还是存在,可用 Hibernate findByid 就会报 该记录已删 的错误.郁闷
22 楼
温柔一刀
2007-04-14
dada 写道
我不认为测试一定要直接操作数据库,尤其是用hibernate的时候。
如果用了hibernate
测试的时候用hsqldb就可以了
21 楼
dada
2007-04-11
dengyin2000 写道
刚刚看了下,确实是拿的session cache中的对象, 根本没有发送select 语句
这段代码的本意就是判断session中的对象是否被删除了。
前头漏了段
public void testDelete() { Sample sample = dao.get(new Long(1)); dao.delete(sample); Object obj = dao.get(new Long(1)); AssertNull(obj); }
我不认为测试一定要直接操作数据库,尤其是用hibernate的时候。
20 楼
dengyin2000
2007-04-11
刚刚看了下,确实是拿的session cache中的对象, 根本没有发送select 语句
19 楼
dengyin2000
2007-04-11
dada 写道
dengyin2000 写道
总结下, 应该commit transaction才会触发session 的flush的吧。
刚才看了下AbstractTransactionalDataSourceSpringContextTests这个类。他是在onSetup的时候开始transaction 然后在onTeardown时commit transaction。 所以如果不显示调用session.flush的话,table里面是不会有变化的。所以我的设想应该是正确的,flushCurrentSession()方法里面拿的是同一个session。
想要看到数据变化的话 在你的测试方法里面调用下flushCurrentSession()方法就行。。
刚才看了下AbstractTransactionalDataSourceSpringContextTests这个类。他是在onSetup的时候开始transaction 然后在onTeardown时commit transaction。 所以如果不显示调用session.flush的话,table里面是不会有变化的。所以我的设想应该是正确的,flushCurrentSession()方法里面拿的是同一个session。
想要看到数据变化的话 在你的测试方法里面调用下flushCurrentSession()方法就行。。
protected SessionFactory getSessionFactory(){ return (SessionFactory) getApplicationContext().getBean("sessionFactory"); } protected void flushCurrentSession(){ Session session = SessionFactoryUtils.getSession(getSessionFactory(), false); if (session !=null){ session.flush(); } }
我觉得改变测试方法比较好:
public void testDelete() { service.delete(new Long(1)); Object obj = service.get(new Long(1)); assertNull(obj); }
刚刚又想到了你这样会不会有问题。看下面的代码,我把delete变成了save
public void testSave() { service.save(new Long(1)); Object obj = service.get(new Long(1)); assertNull(obj); }
因为在testSave中是在一个session中, 所以service.get的话可能根本不会读数据库里面的值, 而是拿的session cache中的?
18 楼
dengyin2000
2007-04-11
Godlikeme 写道
Godlikeme 写道
每次调用,应该是取的不同的session,这样是不对的,参见HibernateTemaplate.executeWithSession
这个问题我看错了,原来问题是jdbctemplate.execute(),不是不同session的问题。
只能显示调用sessionFlush了,hibernateTemplate和jdbcTemplate一块用,这样不一致性的问题就会一直存在。
是的 我没有发现,hibernateTemplate有executeWithSession这个方法。
正规的话 当然是应该用jdbc来测试的。
17 楼
Godlikeme
2007-04-11
Godlikeme 写道
每次调用,应该是取的不同的session,这样是不对的,参见HibernateTemaplate.executeWithSession
这个问题我看错了,原来问题是jdbctemplate.execute(),不是不同session的问题。
只能显示调用sessionFlush了,hibernateTemplate和jdbcTemplate一块用,这样不一致性的问题就会一直存在。
16 楼
Godlikeme
2007-04-11
tsingn 写道
Godlikeme 写道
每次调用,应该是取的不同的session,这样是不对的,参见HibernateTemaplate.executeWithSession
同意!
但是不知道为什么用不同的session flush一下也会起作用?
flush后session是与数据库同步的,因为测试不是多线程,session之间就不会出现不一致的情况。
15 楼
dengyin2000
2007-04-11
dada 写道
dengyin2000 写道
总结下, 应该commit transaction才会触发session 的flush的吧。
刚才看了下AbstractTransactionalDataSourceSpringContextTests这个类。他是在onSetup的时候开始transaction 然后在onTeardown时commit transaction。 所以如果不显示调用session.flush的话,table里面是不会有变化的。所以我的设想应该是正确的,flushCurrentSession()方法里面拿的是同一个session。
想要看到数据变化的话 在你的测试方法里面调用下flushCurrentSession()方法就行。。
刚才看了下AbstractTransactionalDataSourceSpringContextTests这个类。他是在onSetup的时候开始transaction 然后在onTeardown时commit transaction。 所以如果不显示调用session.flush的话,table里面是不会有变化的。所以我的设想应该是正确的,flushCurrentSession()方法里面拿的是同一个session。
想要看到数据变化的话 在你的测试方法里面调用下flushCurrentSession()方法就行。。
protected SessionFactory getSessionFactory(){ return (SessionFactory) getApplicationContext().getBean("sessionFactory"); } protected void flushCurrentSession(){ Session session = SessionFactoryUtils.getSession(getSessionFactory(), false); if (session !=null){ session.flush(); } }
我觉得改变测试方法比较好:
public void testDelete() { service.delete(new Long(1)); Object obj = service.get(new Long(1)); assertNull(obj); }
我有遇到你这种情况, 一个同事使用jdbc去验证的时候 会有问题, 但是我用service去拿的话 就能通过。 最后发现我这里发送了update语句,而用jdbc去验证的话并没有flush。 我不觉得你上面的方式好。 因为我这种方式对于使用jdbc或者其他方式去验证都是有效的, 而且如果我没有get find方法呢? 我还要为测试去加多这样的方法?
14 楼
dada
2007-04-11
dengyin2000 写道
总结下, 应该commit transaction才会触发session 的flush的吧。
刚才看了下AbstractTransactionalDataSourceSpringContextTests这个类。他是在onSetup的时候开始transaction 然后在onTeardown时commit transaction。 所以如果不显示调用session.flush的话,table里面是不会有变化的。所以我的设想应该是正确的,flushCurrentSession()方法里面拿的是同一个session。
想要看到数据变化的话 在你的测试方法里面调用下flushCurrentSession()方法就行。。
刚才看了下AbstractTransactionalDataSourceSpringContextTests这个类。他是在onSetup的时候开始transaction 然后在onTeardown时commit transaction。 所以如果不显示调用session.flush的话,table里面是不会有变化的。所以我的设想应该是正确的,flushCurrentSession()方法里面拿的是同一个session。
想要看到数据变化的话 在你的测试方法里面调用下flushCurrentSession()方法就行。。
protected SessionFactory getSessionFactory(){ return (SessionFactory) getApplicationContext().getBean("sessionFactory"); } protected void flushCurrentSession(){ Session session = SessionFactoryUtils.getSession(getSessionFactory(), false); if (session !=null){ session.flush(); } }
我觉得改变测试方法比较好:
public void testDelete() { service.delete(new Long(1)); Object obj = service.get(new Long(1)); assertNull(obj); }
13 楼
tsingn
2007-04-11
AbstractTransactionalDataSourceSpringContextTests里面的tearDown有两个方法:onTearDownInTransaction和onTearDownAfterTransaction
所以你可以试着把flush的操作放在onTearDownInTransaction里面看看,这样你不用每次都要在测试方法里面调用了!
完了把测试结果贴一下,呵呵。
所以你可以试着把flush的操作放在onTearDownInTransaction里面看看,这样你不用每次都要在测试方法里面调用了!
完了把测试结果贴一下,呵呵。
12 楼
dengyin2000
2007-04-11
总结下, 应该commit transaction才会触发session 的flush的吧。
刚才看了下AbstractTransactionalDataSourceSpringContextTests这个类。他是在onSetup的时候开始transaction 然后在onTeardown时commit transaction。 所以如果不显示调用session.flush的话,table里面是不会有变化的。所以我的设想应该是正确的,flushCurrentSession()方法里面拿的是同一个session。
想要看到数据变化的话 在你的测试方法里面调用下flushCurrentSession()方法就行。。
刚才看了下AbstractTransactionalDataSourceSpringContextTests这个类。他是在onSetup的时候开始transaction 然后在onTeardown时commit transaction。 所以如果不显示调用session.flush的话,table里面是不会有变化的。所以我的设想应该是正确的,flushCurrentSession()方法里面拿的是同一个session。
想要看到数据变化的话 在你的测试方法里面调用下flushCurrentSession()方法就行。。
protected SessionFactory getSessionFactory(){ return (SessionFactory) getApplicationContext().getBean("sessionFactory"); } protected void flushCurrentSession(){ Session session = SessionFactoryUtils.getSession(getSessionFactory(), false); if (session !=null){ session.flush(); } }
11 楼
tsingn
2007-04-11
dada 写道
一个测试方法一个transaction,assertEquals这里session还没有关闭,所以你测试不会通过。
这样说就能够解释了,我一直以为session在dao.delete()方法结束后就关闭了。哈哈
10 楼
dada
2007-04-11
一个测试方法一个transaction,assertEquals这里session还没有关闭,所以你测试不会通过。
发表评论
-
Common reference data in Spring MVC
2010-04-27 16:15 1223http://developingdeveloper.word ... -
[spring jdbc] rowmapper with one-to-many query
2010-04-27 16:03 1315http://forum.springsource.org/s ... -
spring sample petclinic 3.0 maven svn path
2010-02-03 13:21 1513https://src.springframework.org ... -
在google appengine中使用Spring mvc 3.0中遇到的问题
2009-11-16 18:02 16681. 在使用jstl时不需要导入jstl,jsp 和servl ... -
Spring mail sender configruation sample
2009-06-04 15:13 1640<bean id="mailSende ... -
spring 控制hibernate的session何时关闭.
2005-09-13 16:00 2066http://blog.csdn.net/dengyin200 ... -
Spring AOP
2005-11-01 16:00 2046对AOP的概念一直是蒙蒙融融的。而且看Spring的文档上面对 ... -
Spring之FactoryBean(工厂Bean)
2006-04-14 16:00 7349Spring之FactoryBean(工厂Bean) or ... -
Spring之事务管理
2006-04-14 16:00 1724Spring之事务管理 EJB被人骂的够多了,除了SLSB ...
相关推荐
spring单元测试包spring单元测试包spring单元测试包spring单元测试包spring单元测试包
这个"spring websocket 测试项目"是为了帮助开发者理解和实践如何在实际应用中集成和使用WebSocket。 首先,我们要了解Spring WebSocket的基础架构。它基于STOMP(Simple Text Oriented Message Protocol)协议,这...
在本篇文章中,我们将深入探讨Spring 2.5 TestContext测试框架的核心特性和使用方法。 首先,Spring TestContext框架的核心是`@ContextConfiguration`注解,它用于指定测试类中应用上下文的配置。你可以通过此注解...
本示例代码聚焦于使用JUnit进行Spring测试,这是一项核心的Java测试框架,广泛用于编写可重复的、独立的单元测试。 首先,让我们深入理解Spring测试的基本概念。Spring测试支持主要由`spring-test`模块提供,它包含...
9. **AssertJ和Hamcrest**: Spring Test通常与这些强大的断言库结合使用,提供更清晰、表达力更强的断言,帮助编写更具可读性的测试代码。 10. **Mock Beans**: 可以使用`@MockBean`和`@SpyBean`注解在测试上下文中...
在Spring中,我们可以使用`@RunWith(SpringRunner.class)`注解来运行测试类,同时用`@ContextConfiguration`或`@SpringBootTest`注解加载相应的上下文配置。这样,我们可以利用`@Autowired`注解注入依赖,并使用`@...
4. **使用Spring Cloud Contract步骤** - **添加依赖**:在服务提供者和消费者项目中引入Spring Cloud Contract相关依赖。 - **编写契约**:在`src/main/resources/contracts`目录下创建契约文件。 - **配置**:...
最小配置Spring-测试
5. **测试访问控制表达式**:Spring Security允许我们在配置中使用SpEL(Spring Expression Language)表达式来定义访问控制规则。在单元测试中,可以创建特定的访问控制表达式测试用例,确保它们按预期评估。 6. *...
同时,Spring Boot提供了`@SpringBootTest`注解,用于启动一个完整的Spring应用上下文,这样可以在测试中使用到Spring的所有功能。 三、Mockito与Spring Boot测试 Mockito是一个流行的Java单元测试框架,它允许我们...
在进行Spring测试时,开发者通常会使用`@RunWith(SpringRunner.class)`来启用Spring的测试支持,然后通过`@SpringBootTest`或更具体的测试注解来指定测试范围。`@Autowired`注解可以帮助注入需要的bean,而`@Mock...
在Spring3中,我们可以使用JUnit作为主要的测试框架,结合`@RunWith(SpringJUnit4ClassRunner.class)`注解来启动Spring上下文,使得测试类能够访问到Spring的bean。例如: ```java import org.junit.Test; import ...
本文将详细讲解Spring集成测试工具的使用和重要性。 首先,集成测试是在所有组件被组装到一起后进行的测试,目的是发现模块间的接口问题。Spring提供了一些工具和库,如Spring Test、Spring Boot Test和Mockito,来...
这个压缩包“Spring测试框架.rar”包含了与使用Spring 2.5 TestContext测试框架相关的资源,特别是文档“使用 Spring 2.5 TestContext 测试框架.htm”和其相关的文件夹“使用 Spring 2.5 TestContext 测试框架_files...
本文以JD-GUI为例,介绍了如何使用该工具来辅助Spring Cloud的开发和测试。通过有效的工具支持,开发者可以更专注于业务逻辑的实现,减少在基础架构层面上的困扰,从而提高整体项目的开发质量和速度。在实际工作中,...
本指南旨在帮助开发者更好地理解和使用Spring、Spring Boot框架中的TestNG测试工具。TestNG是一个功能强大的测试框架,它提供了比JUnit更多的功能,如并行测试、测试配置、支持多种测试类型等。 **认识TestNG** ...
本文将介绍如何使用 Spring Test 框架对 Spring Cloud 应用程序进行单元测试。 什么是单元测试 单元测试是软件测试的一种,它通过编写测试代码来验证单个软件单元(例如函数、方法、类等)的正确性。单元测试的...
3. **Spring Test**:Spring 提供了自己的测试模块,包含`@RunWith(SpringRunner.class)`注解,它可以将JUnit测试与Spring环境结合,自动加载ApplicationContext,使得我们可以使用依赖注入来测试bean。 4. **@...
为了更好地模拟实际运行环境,我们可能需要在Spring配置文件中定义一些mock bean,或者使用`@MockBean`和`@SpyBean`等Spring Boot测试注解来创建mock对象。这样,我们可以在测试中控制这些mock对象的行为,以便更...