使用JUnit进行单例测试

时间:2015-10-05 05:19:48

标签: java testing junit singleton assert

我有一个单身类,如下所示:

  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()传递,它表示这两个对象完全相同。但是从第二个,TestgetInstance(),它没有通过。

我的问题是:为什么?为什么它没有通过第二次测试。我在想,即使我调用实例方法它应该返回true,因为它们属于完全相同的对象。我错过了一点吗?

2 个答案:

答案 0 :(得分:1)

这类似于this question。您的getInstance()方法返回一个原语,但JUnit的Assert.assertSame(Object, Object)需要2个对象,并检查它们的引用是否指向同一个对象。

在这种情况下,Java将使用自动装箱,实质上是调用Character.valueOf(char)以便为assert方法提供正确的参数。但是,由于这将为每个参数创建一个单独的Character对象,因此断言将失败。

请尝试使用Assert.assertEquals(Object, Object)。这将使用equals(Object)方法。

答案 1 :(得分:1)

您的代码通过了所有测试。它应该。

即使通过assertSame()导致自动装箱,也会为char0-127(包括)返回相同的对象,因为这些值为{{3 }}

这是cached

的源代码
public static Character valueOf(char c) {
    if (c <= 127) { // must cache
        return CharacterCache.cache[(int)c];
    }
    return new Character(c);
}

其行为在其javadoc(摘录)中得到确认:

  

...此方法将始终缓存范围&#39; \ u0000&#39;到&#39; \ u007F&#39;,包括......

自推出以来一直保持不变(版本1.5)。

但是,如果您的代码并返回0-127范围之外的值,例如:

aCharMap.put('c', '¢'); // the "cent" char is decimal 155

然后使用它的测试将失败:

Assert.assertSame(instance1.getInstance('c'), instance2.getInstance('c')); // fails