Как издеваться со статическими методами?
-
03-07-2019 - |
Вопрос
Я новичок в макетировании объектов, но я понимаю, что мне нужно, чтобы мои классы реализовывали интерфейсы, чтобы имитировать их.
Проблема, с которой я сталкиваюсь, заключается в том, что на моем уровне доступа к данным я хочу иметь статические методы, но я не могу поместить статический метод в интерфейс.
Как лучше всего обойти это?Должен ли я просто использовать методы экземпляра (что кажется неправильным) или есть другое решение?
Решение
Я бы использовал шаблон объекта метода.Создайте статический экземпляр этого и вызовите его в статическом методе.Должна быть возможность создания подкласса для тестирования, в зависимости от вашего макетного фреймворка.
т. е.в вашем классе со статическим методом есть:
private static final MethodObject methodObject = new MethodObject();
public static void doSomething(){
methodObject.doSomething();
}
и ваш метод object может быть очень простым, легко тестируемым:
public class MethodObject {
public void doSomething() {
// do your thang
}
}
Другие советы
Да, вы используете методы экземпляра.Статические методы в основном говорят: "Есть один способ реализовать эту функциональность - он не полиморфный". Насмешка опирается на полиморфизм.
Теперь, если ваши статические методы логически не заботятся о том, какую реализацию вы используете, они могли бы принимать интерфейсы в качестве параметров или, возможно, работать вообще без взаимодействия с состоянием - но в противном случае вы должны использовать экземпляры (и, вероятно, внедрение зависимостей для объединения всего вместе).
Я нашел блог через Google с несколькими замечательными примерами того, как это сделать:
Реорганизуйте класс, чтобы он был классом экземпляра и реализовывал интерфейс.
Вы уже заявили, что не хотите этого делать.
Используйте класс экземпляра-оболочки с делегатами для членов статических классов
Делая это, вы можете имитировать статический интерфейс с помощью делегатов.
Используйте класс экземпляра оболочки с защищенными членами, которые вызывают статический класс
Это, вероятно, самый простой способ макетирования / управления без рефакторинга, поскольку он может быть просто унаследован и расширен.
Возможно, вы пытаетесь протестировать слишком глубокую отправную точку.Нет необходимости создавать тест для тестирования каждого метода в отдельности;частные и статические методы должны быть протестированы путем вызова общедоступных методов, которые затем по очереди вызывают частные и статические методы.
Итак, допустим, ваш код выглядит следующим образом:
public object GetData()
{
object obj1 = GetDataFromWherever();
object obj2 = TransformData(obj1);
return obj2;
}
private static object TransformData(object obj)
{
//Do whatever
}
Вам не нужно писать тест для метода transformData (и вы не можете этого сделать).Вместо этого напишите тест для метода getData, который проверяет работу, проделанную в transformData.
Используйте методы экземпляра там, где это возможно.
Используйте public static Func [T, U] (ссылки на статические функции, которые могут быть заменены на фиктивные функции), где методы экземпляра невозможны.
Простое решение состоит в том, чтобы разрешить изменять реализацию статического класса с помощью установщика:
class ClassWithStatics {
private IClassWithStaticsImpl implementation = new DefaultClassWithStaticsImpl();
// Should only be invoked for testing purposes
public static void overrideImplementation(IClassWithStaticsImpl implementation) {
ClassWithStatics.implementation = implementation;
}
public static Foo someMethod() {
return implementation.someMethod();
}
}
Итак, при настройке ваших тестов вы вызываете overrideImplementation
с каким-то издевательским интерфейсом.Преимущество заключается в том, что вам не нужно менять клиентов вашего статического класса.Недостатком является то, что у вас, вероятно, будет немного дублированный код, потому что вам придется повторять методы статического класса и его реализацию.Но иногда статические методы могут использовать другой интерфейс, который обеспечивает базовую функциональность.
Проблема, с которой вы сталкиваетесь, заключается в том, что вы используете сторонний код, и он вызывается из одного из ваших методов.В итоге мы заключили это в объект и вызвали передачу его с помощью dep inj, а затем ваш модульный тест может имитировать статический метод третьей стороны, вызывающий установщик с его помощью.