Java инструмент для тестирования частных методов? - PullRequest
7 голосов
/ 16 августа 2011

Существуют различные мнения о значимости тестирования частных методов, например, здесь и здесь . Я лично думаю, что это имеет смысл, вопрос в том, как это сделать правильно. В C ++ вы можете использовать #define hack или создать тестовый класс friend, в C # есть InternalsVisibleToAttribute , но в Java мы должны либо использовать отражение или сделать их «видимыми для тестирования» и аннотировать их как таковые , чтобы прояснить намерение. Недостатки обоих должны быть вполне понятны.

Я думаю, что должно быть что-то лучше. Начиная с

public class Something {
    private int internalSecret() {
        return 43;
    }
}

было бы неплохо иметь возможность вызывать закрытые методы в тестовом коде, например

@MakeVisibleForTesting Something something = new Something();
Assert.assertEquals(43, something.internalSecret());

Здесь аннотация молча преобразует все вызовы в частные методы something, используя отражение. Интересно, может ли Ломбок это сделать (и спросит у авторов).

Вполне возможно, что создание такого количества магии оказывается слишком сложным, и в любом случае это займет некоторое время, поэтому я ищу какую-то альтернативу. Возможно, аннотируем тестируемый класс чем-то вроде @Decapsulate и используем процессор аннотаций для генерации класса Decapsulated_Something, похожего на

public class Decapsulated_Something {
    public Decapsulated_Something(Something delegate) {
        this.delegate = delegate
    }
    public boolean internalSecret() {
        // call "delegate.internalSecret()" using reflection
    }
    ...
}

, что позволило бы использовать

Decapsulated_Something something = new Decapsulated_Something(new Something());
Assert.assertEquals(43, something.internalSecret());

У меня нет большого опыта работы с аннотациями, поэтому сначала я спрашиваю:

  • Насколько сложно это реализовать?
  • Что я забыл?
  • Что вы вообще об этом думаете?

Ответы [ 5 ]

7 голосов
/ 16 августа 2011

Внедрение этой реализации кажется большим трудом. Это может не стоить того. Скорее просто установите пакет методов по умолчанию.

Однако, если вы решили вызвать закрытый метод, вы можете использовать setAccessible в своем классе Decapsulated_something, чтобы разрешить вызов через отражение. Так что все довольно просто.

1 голос
/ 18 ноября 2011

было бы неплохо иметь возможность вызывать закрытые методы в тестовом коде, такие как

@MakeVisibleForTesting Something something = new Something();
Assert.assertEquals(43, something.internalSecret());

Есть такая вещь, как аннотация метода, проверьте dp4j s @TestPrivates:

@Test
@TestPrivates 
//since the method is annotated with JUnit's @Test this annotation is redundant. 
// You just need to have dp4j on the classpath.
    public void somethingTest(){
      Something something = new Something();
      int sthSecret = something.internalSecret();
       Assert.assertEquals(43, sthSecret); //cannot use something.internalSecret() directly because of bug [dp4j-13][2] 
    }
1 голос
/ 16 августа 2011

Несколько лет назад я работал над проектом, который генерировал классы, чтобы упростить юнит-тестирование частных методов. http://java.net/projects/privateer/

Он генерировал дополнительные классы, которые сделали это проще, чем вызов рефлексии, например если бы у вас был MyClass.myPrivateMethod (), он сгенерировал бы класс _MyClass, который позволял бы напрямую вызывать myPrivateMethod.

Он никогда не был действительно закончен и был несколько полезен для некоторых случаев, но в целом я бы не рекомендовал тестировать частные методы, если в этом нет крайней необходимости. Обычно лучше преобразовать их в служебные классы (с доступом к пакетам, если вы беспокоитесь о том, чтобы пользователи их использовали).

1 голос
/ 16 августа 2011

Есть несколько подходов, чтобы взять

  • Не тестируйте приватные методы, поскольку они являются скрытыми деталями реализации, которые никогда не должны иметь значения для вызывающей стороны.
  • Сделайте пакет методов локальным, чтобы вызывающий не мог получить к ним доступ, но вы можете получить к ним доступ в том же пакете, то есть в модульном тесте.
  • Сделать модульный тест внутренним классом или предоставить пакет локального внутреннего класса. Не уверен, что это улучшение!
  • Использовать отражение для доступа к методам класса. Это похоже на маркировку метода rpivate, когда его нет, и это путаница ИМХО. Вы должны помечать метод как приватный, только когда он действительно приватный.
1 голос
/ 16 августа 2011

Я отвечу на вопрос «В общем» :-) Чтобы сделать метод доступным через отражение, требуется всего несколько строк кода, и существует довольно много библиотек, утилит, API и т. Д., Которые предоставляют методы для этого.,Также, возможно, есть много разных техник, которые вы могли бы использовать в своем собственном коде.Например, манипулирование байт-кодом, отражение, расширения классов и т. Д. Но я был бы склонен упростить ситуацию.Хотя это может быть полезно для тестирования частных методов, также вероятно, что вы захотите протестировать только несколько.Поэтому разработка чего-то сложного, вероятно, излишня.Я просто использовал бы установленный API или написал бы быстрый метод для доступа к частным методам, которые меня интересовали, и позволил бы это сделать на этом.

...