使用 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() 导致自动装箱,也会为 char0-127(含)返回 相同的 对象,因为那些值为 cached.

这是Character.valueOf(char c)

的源代码
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