Как издеваться со статическими методами? - PullRequest
34 голосов
/ 30 сентября 2008

Я новичок в области макетов объектов, но я понимаю, что мне нужно, чтобы мои классы реализовывали интерфейсы, чтобы имитировать их.

Проблема, с которой я столкнулся, заключается в том, что на моем уровне доступа к данным мне нужны статические методы, но я не могу поместить статический метод в интерфейс.

Какой лучший способ обойти это? Должен ли я просто использовать методы экземпляра (что кажется неправильным) или есть другое решение?

Ответы [ 7 ]

26 голосов
/ 30 сентября 2008

Я нашел блог через Google с несколькими замечательными примерами того, как это сделать:

  1. Преобразуйте класс в класс экземпляра и реализуйте интерфейс.

    Вы уже заявили, что не хотите этого делать.

  2. Использование класса экземпляра оболочки с делегатами для членов статических классов

    Делая это, вы можете моделировать статический интерфейс через делегатов.

  3. Используйте класс экземпляра оболочки с защищенными членами, которые вызывают статический класс

    Это, вероятно, самый простой способ моделирования / управления без рефакторинга, поскольку он может быть просто унаследован от и расширен.

26 голосов
/ 30 сентября 2008

Да, вы используете методы экземпляра. Статические методы в основном говорят: «Есть один способ реализовать эту функциональность - он не полиморфный». Насмешка опирается на полиморфизм.

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

22 голосов
/ 30 сентября 2008

Я бы использовал шаблон объекта метода. Имейте статический экземпляр этого и вызывайте его в статическом методе. Должна быть возможность создания подкласса для тестирования, в зависимости от вашей фальшивой среды.

т.е. в вашем классе со статическим методом есть:

private static final MethodObject methodObject = new MethodObject();

public static void doSomething(){
    methodObject.doSomething();
}

и ваш метод объекта может быть очень простым, легко проверяемым:

public class MethodObject {
    public void doSomething() {
        // do your thang
    }
}
5 голосов
/ 30 сентября 2008

Возможно, вы пытаетесь проверить слишком глубоко в начальной точке. Нет необходимости создавать тест для тестирования каждого метода в отдельности; Закрытые и статические методы должны быть проверены путем вызова открытых методов, которые затем по очереди вызывают закрытые и статические методы.

Допустим, ваш код выглядит так:

public object GetData()
{
 object obj1 = GetDataFromWherever();
 object obj2 = TransformData(obj1);
 return obj2;
} 
private static object TransformData(object obj)
{
//Do whatever
}

Вам не нужно писать тест для метода TransformData (и вы не можете). Вместо этого напишите тест для метода GetData, который проверяет работу, выполненную в TransformData.

4 голосов
/ 30 сентября 2008

По возможности используйте методы экземпляра.

Использовать общедоступный статический Func [T, U] (ссылки на статические функции, которые можно заменить на фиктивные функции), где методы экземпляра невозможны.

0 голосов
/ 15 июля 2009

Проблема в том, что вы используете сторонний код, и он вызывается одним из ваших методов. В итоге мы завернули его в объект и вызвали, передав его с помощью dep inj, и тогда ваш модульный тест может подделать сторонний статический метод, который вызывает метод setter.

0 голосов
/ 30 сентября 2008

Простое решение - изменить реализацию статического класса с помощью установщика:

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 с каким-то поддельным интерфейсом. Преимущество заключается в том, что вам не нужно менять клиентов вашего статического класса. Недостатком является то, что у вас, вероятно, будет небольшой дублированный код, потому что вам придется повторять методы статического класса и его реализацию. Но иногда статические методы могут использовать более легкий интерфейс, который обеспечивает базовую функциональность.

...