2017-02-20 143 views
0

我对如何组织和测试代码有如下概念上的疑问,其中对辅助方法的调用是该类的所有公共方法的第一条指令。我的想法是使代码干净和可测试。如何组织和测试此代码?

该代码是一个例子,试图通过类“缓存”来说明这一点。如果设置了此类,则可选前缀将应用于缓存中的所有键。

import java.util.HashMap; 


public class Cache { 
    private HashMap<String, Integer> inMemoryCache; 
    private String prefix; 


    public Cache() { 
     this.inMemoryCache = new HashMap<String, Integer>(); 
     prefix = null; 
    } 

    public void setPrefix(String prefix) { 
     this.prefix = prefix; 
    } 

    public int getValue(String key) throws NullPointerException { 
     String prefixedKey = applyPrefixOrDefault(key); 
     return inMemoryCache.get(prefixedKey); 
    } 

    public void setValue(String key, int value) { 
     String prefixedKey = applyPrefixOrDefault(key); 
     inMemoryCache.put(prefixedKey, value); 
    } 

    public boolean isCached(String key) { 
     String prefixedKey = applyPrefixOrDefault(key); 
     return inMemoryCache.containsKey(prefixedKey); 
    } 

    private String applyPrefixOrDefault(String key) { 
     if (prefix == null) { 
      return key; 
     } else { 
      return prefix + key; 
     } 
    } 


    public static void main (String[] arg) { 
     Cache cache = new Cache(); 
     cache.setPrefix("global:"); 
     cache.setValue("id", 4); 
     int value = cache.getValue("id"); 
     System.out.println(value); 
    } 
} 

此代码提出了两个问题,对我说:

  1. 如果我有很多方法访问内部哈希表,那会是正确的独立缓存的一个类的行为和行为其他的前缀?

  2. 什么是最简洁的方式来测试呢?如果我们不考虑前缀,则测试getValue,setValue和isCached非常简单。使用前缀我们需要测试两件事情,即缓存的正确内部行为,并且我们还需要测试所有方法在访问数据之前调用applyPrefixOrDefault。

这是一个常见用例,我确定必须有一些设计模式来组织这个。任何想法?

回答

1

在我看来,我们在这里错过的是一个构造函数,让我们设置缓存的状态。所以,我想补充一个如下:

public Cache() { 
    this(null, new HashMap<String, Integer>()); 
} 

public Cache(String prefix, Map<String, Integer> cache) { 
    this.prefix = prefix; 
    this.inMemoryCache = cache; 
} 

有了这个新的构造函数,你应该能够编写的测试用例的每一个可能的高速缓存状态。我还会将applyPrefixOrDefault方法的可见性更改为受保护或包,以便测试代码可以访问它。例如,测试GetValue方法,我会写:

public class EmptyCacheTests { 

    private final Map<String, Integer> memory; 
    private final String prefix; 
    private final Cache cache; 

    public EmptyCacheTests() { 
     this.memory = new HasMap<String, Integer>(); 
     this.prefix = "foo"; 
     this.cache = new Cache(prefix, memory); 
    } 

    public void testGetValue() { 
     String key = this.cache.applyPrefixOrDefault("bar") 
     this.memory.put(key, 50); 
     result = this.cache.getValue("bar"); 
     assertEquals(50, result, "The value retrieved is wrong!"); 
    } 
} 

这里的点,它允许测试设置缓存的内部状态,这样我们就可以测试对许多不同的人。

+0

如果我有很多方法(例如10-20个方法),你会考虑在一个单独的类中分离前缀的行为,还是你会复制所有的测试用例(带前缀和不带前缀)? – Garet

+0

是的,如果您想要使用和不使用前缀进行测试,将前缀计算分离到单独的类中可能会让您按构图构建测试,而不是枚举所有可能的测试用例。 – Franck

+0

考虑它,'prefix'属性与缓存无关,而与密钥的计算/转换无关。因此,我会创建一个KeyBuilder对象,它将封装这个前缀,并且会公开一个类似于'applyPrefixOrDefault'的'transformKey'方法。然后可以在缓存的构造函数中注入KeyBuilder对象,以便测试可以定义它。 – Franck