使用 JUnit 进行单例测试
Singleton Test with JUnit
我有一个单身人士 class,如下所示:
public enum SingletonClassA {
INSTANCE;
private final Map<Character, Character> characters;
// private constructor
SingletonClassA() {
Map<Character, Character> aCharMap = new HashMap();
aCharMap.put('a', 'e');
aCharMap.put('o', 'u');
// in order to keep short I erased other puts.
characters = aCharMap;
}
public char getInstance(final char letter) {
return characters.get(letter);
}
public boolean containsKey(char letter) {
return characters.containsKey(letter);
}
}
并且为了测试我只创建了一个对象,即使我调用了不止一次,我用 JUnit 创建了一个测试用例:
public class SingletonTest {
@Test
public void TestSingletonObject(){
SingletonClassA instance1 = SingletonClassA.INSTANCE;
SingletonClassA instance2 = SingletonClassA.INSTANCE;
//Passes
Assert.assertSame("2 objects are same", instance1, instance2);
}
@Test
public void TestgetInstance(){
SingletonClassA instance1 = SingletonClassA.INSTANCE;
SingletonClassA instance2 = SingletonClassA.INSTANCE;
// Does not pass
Assert.assertSame(instance1.getInstance('o'), instance2.getInstance('o'));
}
}
测试从 TestSingletonObject() 中通过,它表示这 2 个对象完全相同。但是从第二个 TestgetInstance() 开始,它没有通过。
我的问题是:为什么?为什么它没有通过第二次测试。我在想,即使我调用实例方法,它也应该 return true 因为它们属于完全相同的对象。我漏掉了一点吗?
这类似于this question。您的 getInstance()
方法 returns 是原始方法,但是 JUnit 的 Assert.assertSame(Object, Object)
需要 2 个对象,并且会检查它们的引用是否指向同一个对象。
Java 在这种情况下将使用自动装箱,本质上是调用 Character.valueOf(char)
以便为断言方法提供正确的参数。但是,由于这将为每个参数创建一个单独的 Character
对象,因此断言将失败。
请尝试使用 Assert.assertEquals(Object, Object)
。这将使用 equals(Object)
方法。
您的代码通过了所有测试。它应该。
即使 assertSame()
导致自动装箱,也会为 char
值 0-127
(含)返回 相同的 对象,因为那些值为 cached.
的源代码
public static Character valueOf(char c) {
if (c <= 127) { // must cache
return CharacterCache.cache[(int)c];
}
return new Character(c);
}
其行为在其 javadoc(摘录)中得到确认:
... This method will always cache values in the range '\u0000' to '\u007F', inclusive ...
自推出以来(在版本 1.5 中)一直保持不变。
但是,如果你的代码和returns值超出了0-127的范围,例如:
aCharMap.put('c', '¢'); // the "cent" char is decimal 155
那么使用它的测试将失败:
Assert.assertSame(instance1.getInstance('c'), instance2.getInstance('c')); // fails
我有一个单身人士 class,如下所示:
public enum SingletonClassA {
INSTANCE;
private final Map<Character, Character> characters;
// private constructor
SingletonClassA() {
Map<Character, Character> aCharMap = new HashMap();
aCharMap.put('a', 'e');
aCharMap.put('o', 'u');
// in order to keep short I erased other puts.
characters = aCharMap;
}
public char getInstance(final char letter) {
return characters.get(letter);
}
public boolean containsKey(char letter) {
return characters.containsKey(letter);
}
}
并且为了测试我只创建了一个对象,即使我调用了不止一次,我用 JUnit 创建了一个测试用例:
public class SingletonTest {
@Test
public void TestSingletonObject(){
SingletonClassA instance1 = SingletonClassA.INSTANCE;
SingletonClassA instance2 = SingletonClassA.INSTANCE;
//Passes
Assert.assertSame("2 objects are same", instance1, instance2);
}
@Test
public void TestgetInstance(){
SingletonClassA instance1 = SingletonClassA.INSTANCE;
SingletonClassA instance2 = SingletonClassA.INSTANCE;
// Does not pass
Assert.assertSame(instance1.getInstance('o'), instance2.getInstance('o'));
}
}
测试从 TestSingletonObject() 中通过,它表示这 2 个对象完全相同。但是从第二个 TestgetInstance() 开始,它没有通过。
我的问题是:为什么?为什么它没有通过第二次测试。我在想,即使我调用实例方法,它也应该 return true 因为它们属于完全相同的对象。我漏掉了一点吗?
这类似于this question。您的 getInstance()
方法 returns 是原始方法,但是 JUnit 的 Assert.assertSame(Object, Object)
需要 2 个对象,并且会检查它们的引用是否指向同一个对象。
Java 在这种情况下将使用自动装箱,本质上是调用 Character.valueOf(char)
以便为断言方法提供正确的参数。但是,由于这将为每个参数创建一个单独的 Character
对象,因此断言将失败。
请尝试使用 Assert.assertEquals(Object, Object)
。这将使用 equals(Object)
方法。
您的代码通过了所有测试。它应该。
即使 assertSame()
导致自动装箱,也会为 char
值 0-127
(含)返回 相同的 对象,因为那些值为 cached.
public static Character valueOf(char c) {
if (c <= 127) { // must cache
return CharacterCache.cache[(int)c];
}
return new Character(c);
}
其行为在其 javadoc(摘录)中得到确认:
... This method will always cache values in the range '\u0000' to '\u007F', inclusive ...
自推出以来(在版本 1.5 中)一直保持不变。
但是,如果你的代码和returns值超出了0-127的范围,例如:
aCharMap.put('c', '¢'); // the "cent" char is decimal 155
那么使用它的测试将失败:
Assert.assertSame(instance1.getInstance('c'), instance2.getInstance('c')); // fails