2015-10-05 9 views
1

У меня есть класс синглтон, как показано ниже:Singleton Тест с JUnit

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(), он не проходит.


Мой вопрос: почему? Почему это не проходит от второго теста. Я думаю, что даже я называю методы экземпляра, он должен возвращать true, потому что они принадлежат одному и тому же объекту. Я пропустил пункт?

ответ

1

Это похоже на this question. Ваш метод getInstance() возвращает примитив, но для Assert.assertSame(Object, Object) JUnit требуется 2 объекта и будет проверять, что их ссылки указывают на один и тот же объект.

В этом случае Java будет использовать авто-бокс, по существу вызывающий Character.valueOf(char), чтобы предоставить правильные аргументы методу assert. Однако, поскольку для каждого аргумента будет создан отдельный объект Character, утверждение не будет выполнено.

Попробуйте вместо этого использовать Assert.assertEquals(Object, Object). Это будет использовать метод equals(Object).

1

Ваш код передает все тесты. И это должно быть.

Даже через assertSame() вызывает автоматический бокс, объект же возвращается для char значений 0-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 (выдержка):

... Этот метод будет всегда значения кэша в диапазоне '\ u0000' до '\ u007F', включительно ...

, который не изменился с момента его введения (в версии 1.5).

Однако, если ваш код и возвращает значения вне диапазона 0-127, например:

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

затем тест с использованием его не получится:

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