上周六在杭州的《互联网软件测试大会》上做演讲的时候提到可测试性的话题,顺手举了一个例子:“B类存在对A类的依赖,A类是一个Singleton类,B类使用到了A类中的一个需要被mock的函数,这种情况下如何处理?” 本来,这是《修改代码的艺术》上曾经提到的一个典型模式,该书中有非常详细的描述。但今天收到某位听众的邮件,问这个问题应该怎么回答。
正好好久没有写过blog了,于是顺手写了一段简单的代码来说明这个问题。
问题:
类Singleton是一个单件类,该类实现了一个名为getUserName()的函数,getUserName函数需要连接到数据库并从数据库中取出用户名称。类DependsOnSingleton类是被测类,该类中的sayHello函数使用到了Singleton类的getUserName函数,在对DependsOnSingleton类进行单元测试的时候,显然我们并不想设置一个真正的数据库,所以最理想的情况是使用mock方式得到一个可以被控制的Singleton类的getUserName函数的实现。如果Singleton类不是一个单件类,这件事情非常简单,使用接口提取的方法从Singleton类提取接口,然后就可以使用mock技术了。但由于Singleton是一个单件类,这件事情就比较棘手了:Singleton.getInstance会返回一个由getInstance自身逻辑决定的Singleton对象,这样就没法直接塞入一个mock对象了。
代码:
1 public class Singleton {
2 static private Singleton _instance;
3 public final String userName = "Dennis";
4
5 private Singleton() {
6 }
7
8 static Singleton getInstance() {
9 if(null == _instance) {
10 _instance = new Singleton();
11 }
12 return _instance;
13 }
14
15 String getUserName() throws Exception{
16 // Connect to DB and return data from DB
17 // Throw Exception instead
18 throw new Exception("There's no DB exist");
19 }
20 }
2 static private Singleton _instance;
3 public final String userName = "Dennis";
4
5 private Singleton() {
6 }
7
8 static Singleton getInstance() {
9 if(null == _instance) {
10 _instance = new Singleton();
11 }
12 return _instance;
13 }
14
15 String getUserName() throws Exception{
16 // Connect to DB and return data from DB
17 // Throw Exception instead
18 throw new Exception("There's no DB exist");
19 }
20 }