2016-05-03 3 views
2

У меня есть класс Swift, который я тестирую на модуле. Основной целью этого класса является создание HTTP-вызовов. Я только что закончил издеваться над всеми сетевыми запросами, используя Mockingjay, но я хочу убедиться, что в будущем я не забываю издеваться над будущими запросами. В то время как я делал первоначальное издевательство, я заменил базовый URL, который я использую, с тем, который не работает, но я хотел бы оставить это на месте только для моих тестов. Класс испытываемого выглядит следующим образом:Как переопределить класс-свойство Swift для тестирования

public class MyWebServiceWrapper { 
    ... 

    public class var baseURL: String { 
     return "https://api.thesite.com" 
    } 

    ... 
} 

Я пытался использовать OCMock из класса Objective-C, чтобы заменить baseURL «s реализация, и я попытался с помощью метода swizzling as described on NSHipster а (I сделал класс из NSObject и заменил baseURL на метод вместо указанного выше свойства - я бы предпочел не swizzle, тем более, что мне не нужен класс, который должен быть подклассом NSObject).

Это код, который я использовал, чтобы выполнить попытку swizzle, которая не имела никакого эффекта. Для обоих покушений решений ниже, я переписал мой класс тестируемой как так (так как это выглядело, как ни один подход не будет хорошо работать с Swift свойствами или чисто Swift классов):

@objc public class MyWebServiceWrapper: NSObject { 
    ... 

    public class var baseURL: String { 
     return baseURLValue() 
    } 

    public class func baseURLValue() -> String { 
     return "https://api.thesite.com" 
    } 

    ... 
} 

Это был мой swizzling попытки (в Swift) , Основываясь на журнале, я каждый раз нажимаю оператор else, если он помогает понять, что происходит.

extension MyWebServiceWrapper { 

    public override class func initialize() { 
     struct Static { 
      static var token: dispatch_once_t = 0 
     } 

     if self !== MyWebServiceWrapper.self { 
      return 
     } 

     dispatch_once(&Static.token) { 
      NSLog("Replacing MyWebServiceWrapper base URL...") 
      let originalSelector = #selector(baseURLValue) 
      let swizzledSelector = #selector(networkFreeBaseURL) 

      guard let klass = object_getClass(self) else { 
       return 
      } 

      let originalMethod = class_getClassMethod(klass, originalSelector) 
      let swizzledMethod = class_getClassMethod(klass, swizzledSelector) 

      let didAddMethod = class_addMethod(klass, originalSelector, 
               method_getImplementation(swizzledMethod), 
               method_getTypeEncoding(swizzledMethod)) 

      if didAddMethod { 
       NSLog("MyWebServiceWrapper method added") 
       class_replaceMethod(klass, swizzledSelector, method_getImplementation(originalMethod), 
            method_getTypeEncoding(originalMethod)) 
      } else { 
       method_exchangeImplementations(originalMethod, swizzledMethod) 
       NSLog("MyWebServiceWrapper implementation replaced") 
      } 
     } 
    } 

    class func networkFreeBaseURL() -> String { 
     return "https://tests-shouldnt-hit-the-network.com" 
    } 

} 

Вот как я попытался заменить метод с помощью OCMock (в Objective-C). Код вызывается во время конфигурации моих модульных тестов.

id wrapperMock = OCMClassMock([MyWebServiceWrapper class]); 
OCMStub(ClassMethod([wrapperMock baseURLValue])).andReturn(@"https://tests-shouldnt-hit-the-network.com"); 

Что такое правильный способ для достижения своей цели возвращения недопустимого значения из baseURL?

+0

Вы должны найти другой путь, потому что в противном случае это обходной путь :( ли вы какие-либо решения – denis631

+1

@ denis631 я до сих пор? используя ответ, который я привел ниже – Dov

+0

Грустный ... Это просто не похоже на правду, но вы знаете ... GTD: ПОЛУЧИТЕ ВЕЩИ :) – denis631

ответ

1

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

public class MyWebServiceWrapper { 
    ... 

    /// Only use for testing! 
    internal static var baseURLOverride: String? 

    public class var baseURL: String { 
     return baseURLOverride ?? "https://api.thesite.com" 
    } 

    ... 
} 

И внутри моей тестовой конфигурации:

@testable 
import MyFramework 

... 

// Inside test configuration 
MyWebServiceWrapper.baseURLOverride = "https://tests-shouldnt-hit-the-network.com" 
Смежные вопросы