如何对Jalor3的Business做单元测试

举报
开发者学堂小助 发表于 2017/10/18 15:40:36 2017/10/18
【摘要】 我们在写一个Business的时候,除了继承一个用于作单元测试的基类外,基本不用再做其它的事情,即可对待测试的Business方法进行任何透明的调用,无需进行任何特殊处理,就像写正常的业务逻辑一样。

Jalor3的所有业务代码,基本上都是写在Business类里,再由EJB的Facade类提供事务支持。在不Mock数据库操作的情况下,如何要对Business进行单元测试,是非常困难的。在几经试验与研究之后,我们得到了一个相对比较优雅的解决方案。之所以说它是比较优雅的原因是:我们在写一个Business的时候,除了继承一个用于作单元测试的基类外,基本不用再做其它的事情,即可对待测试的Business方法进行任何透明的调用,无需进行任何特殊处理,就像写正常的业务逻辑一样。下面是对应的基类代码:

-
Java 代码
001import static org.powermock.api.mockito.PowerMockito.mock;
002import static org.powermock.api.mockito.PowerMockito.mockStatic;
003import static org.powermock.api.mockito.PowerMockito.when;
004 
005import java.io.PrintWriter;
006import java.sql.Connection;
007import java.sql.DriverManager;
008import java.sql.SQLException;
009import java.sql.SQLFeatureNotSupportedException;
010import java.util.Properties;
011 
012import javax.sql.DataSource;
013 
014import org.apache.log4j.Logger;
015import org.junit.Before;
016import org.junit.runner.RunWith;
017import org.powermock.core.classloader.annotations.PrepareForTest;
018import org.powermock.modules.junit4.PowerMockRunner;
019 
020import com.huawei.it.BaseDbTestCase;
021import com.huawei.it.common.Jdbcs;
022import com.huawei.it.core.frame.ServiceLocator;
023import com.huawei.ormapping.sqlmap.client.SqlMapClientBuilder;
024 
025@RunWith(PowerMockRunner.class)
026@PrepareForTest({ServiceLocator.class, SqlMapClientBuilder.class})
027public abstract class BaseBusinessTestCase extends BaseDbTestCase{
028    private static String url;
029    private static String usr;
030    private static String pwd;
031     
032    static {
033        try {
034            //加载数据库配置信息
035            Properties dbs = new Properties();
036            dbs.load(BaseDbTestCase.class.getResourceAsStream("/com/huawei/it/db.properties"));
037            if(!dbs.isEmpty()){
038                url = dbs.getProperty("url");
039                usr = dbs.getProperty("usr");
040                pwd = dbs.getProperty("pwd");
041            }            
042            //加载数据库驱动
043            Class.forName("oracle.jdbc.driver.OracleDriver");    
044            Jdbcs.setDataSource(getDataSource());
045        catch (Exception e) {
046            throw new RuntimeException(e);
047        }
048    }
049     
050    protected static synch ronized DataSource getDataSource() {
051        return new DataSource() {
052             
053            @Override
054            public <T> T unwrap(Class<T> arg0) throws SQLException {
055                return null;
056            }
057             
058            @Override
059            public boolean isWrapperFor(Class<?> arg0) throws SQLException {
060                return false;
061            }
062             
063            @Override
064            public void setLoginTimeout(int arg0) throws SQLException {
065            }
066             
067            @Override
068            public void setLogWriter(PrintWriter arg0) throws SQLException {                
069            }
070             
071            public Logger getParentLogger() throwsSQLFeatureNotSupportedException {
072                return null;
073            }
074             
075            @Override
076            public int getLoginTimeout() throws SQLException {
077                return 0;
078            }
079             
080            @Override
081            public PrintWriter getLogWriter() throws SQLException {
082                return new PrintWriter(System.out);
083            }
084             
085            @Override
086            public Connection getConnection(String username, String password)
087                    throws SQLException {
088                return DriverManager.getConnection(url, username, password);
089            }
090             
091            @Override
092            public Connection getConnection() throws SQLException {
093                return DriverManager.getConnection(url, usr, pwd);
094            }
095        };
096    }
097     
098    /**
099     * 准备Mock对象,置换框架组件相关方法
100     * @throws Exception
101     */
102    @Before
103    public void setUp()throws Exception{
104        ServiceLocator serviceLocator = mock(ServiceLocator.class);
105        mockStatic(ServiceLocator.class);
106        when(ServiceLocator.getInstance()).thenReturn(serviceLocator);
107        when(serviceLocator.getDataSource("jdbc/jalor3DS")).thenReturn(getDataSource());
108         
109    }
110     
111}

这里需要注意的是代码中有两个地方,一个是数据库连接串、用户名、密码的配置文件路径/com/huawei/it/db.properties,另一个是系统所连数据源的JNDI名称,如jdbc/jalor3DS,在实际使用的时候,要替换成自己的实际值。

下面是一个具体Business的测试类,除了通过JDBC做测试前的准备(清理测试环境)和测试后测试数据的删除外,其它都是直接对Business方法进行的直接调用,对调用后的结果进行断言检查。

-
Java 代码
01import static org.junit.Assert.assertEquals;
02import static org.junit.Assert.assertTrue;
03 
04import java.util.Date;
05 
06import org.junit.After;
07import org.junit.Before;
08import org.junit.Test;
09 
10import com.huawei.it.common.DateUtil;
11import com.huawei.it.common.Jdbcs;
12import com.huawei.it.tcsm.busi.BaseBusinessTestCase;
13import com.huawei.it.tcsm.busi.TcsmCommonBusiness;
14import com.huawei.it.tcsm.vo.MailVO;
15import com.huawei.it.tcsm.vo.TcsmLogVO;
16 
17public class GetLoginLog extends BaseBusinessTestCase {
18    private TcsmCommonBusiness busi = new TcsmCommonBusiness();
19    private TcsmLogVO tcsmLogVO = new TcsmLogVO();
20     
21    @Before
22    public void init()throws Exception {
23        String usrId = "441047706911511";
24        Jdbcs.executeUpdate("delete TPL_HUAWEI_LOG_EVENTS_T where USERID=?", usrId);
25         
26        tcsmLogVO.setUserid(usrId);
27        tcsmLogVO.setClass0("TcsmCommon");
28        tcsmLogVO.setHostip("10.37.55.14");
29        tcsmLogVO.setHostname("zhuodefang.huawei.com");
30        tcsmLogVO.setOperate_object("TcsmCommon");
31        tcsmLogVO.setOperate("Login");
32        tcsmLogVO.setOperate_object_id(String.valueOf(System.currentTimeMillis()));
33        tcsmLogVO.setModule("tcsm_common");
34        tcsmLogVO.setMessage("insert a new record");
35        busi.tcsmLog(tcsmLogVO);
36    }
37     
38    @Test
39    public void getLoginLog()throws Exception{
40        MailVO m = busi.getLoginLog(tcsmLogVO.getUserid());
41        assertEquals(tcsmLogVO.getHostip(), m.getMailAddress());
42        String dateTime = DateUtil.format(new Date(), "yyyy-MM-dd");
43        assertTrue(m.getLastUpdateDate().contains(dateTime));
44    }
45     
46    @After
47    public void tearDown() throws Exception {
48        Jdbcs.executeUpdate("delete TPL_HUAWEI_LOG_EVENTS_T where USERID=?", tcsmLogVO.getUserid());
49    }
50}

基本上只要继承BaseBusinessTestCase这个测试基类(修改里面的数据源JNDI名和数据库相关配置),后面的一切都非常自然,没有任何的侵入性。至于具体的原理,主要是用到了PowerMock这个Mock框架,对系统中的部分静态方法调用进行了Stub,如ServiceLocator.getDataSource(),ServiceLocator.getInstance,关于PowerMock详细的资料,可以上网搜索,非常多,不在这里讨论。如果有兴趣,欢迎回帖探讨。


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。