我想在不啓動模擬器的情況下使用OCUnit在Xcode 4中運行測試。請不要試圖說服我,我正在做單元測試錯誤或類似的事情。我喜歡以傳統的方式進行TDD:在測試中爲類編寫API,然後讓類通過測試。我將編寫單獨的測試,這些測試是在模擬器中運行的端到端測試。在沒有啓動模擬器的情況下在Xcode 4中運行邏輯測試
如果沒有辦法做到這一點,那麼請有人告訴我如何讓測試工具不實例化整個應用程序?我的應用程序是事件驅動的,當它啓動時,我的測試混亂了,它發送了一堆事件。
我想在不啓動模擬器的情況下使用OCUnit在Xcode 4中運行測試。請不要試圖說服我,我正在做單元測試錯誤或類似的事情。我喜歡以傳統的方式進行TDD:在測試中爲類編寫API,然後讓類通過測試。我將編寫單獨的測試,這些測試是在模擬器中運行的端到端測試。在沒有啓動模擬器的情況下在Xcode 4中運行邏輯測試
如果沒有辦法做到這一點,那麼請有人告訴我如何讓測試工具不實例化整個應用程序?我的應用程序是事件驅動的,當它啓動時,我的測試混亂了,它發送了一堆事件。
在你的情況,我假設你有一個單獨的邏輯測試和應用程序測試目標(如果沒有 - 你需要)。在您的方案配置中,您可以定義爲「測試」方案構建的目標。如果您的應用程序測試沒有運行,模擬器將不會啓動。
我懷疑你可能試圖在「應用程序測試」目標(例如Xcode默認創建的目標)中運行'邏輯測試'。查看更多關於這個區別here(以及如何設置)。
我用GHUnit來創建兼容osx/ios的測試套件。有幾個問題,但我發現它比OCUnit更可靠/兼容/直接。
GHUnit爲OS X和iOS提供了基本的模板項目,使初始設置變得簡單。
注:我通常只使用我自己的套件進行大多數測試。
請有人能告訴我如何讓測試工具不實例化整個應用程序?我的應用程序是事件驅動的,當它啓動時,我的測試混亂了,它發送了一堆事件。
我使用Xcode 4的內置測試。應用程序實例化可能看起來很痛苦,但是當我在Xcode Unit Testing: The Good, the Bad, the Ugly上編寫時,它可以在不區分邏輯測試和應用程序測試的情況下編寫測試。具體來說,它允許我爲視圖控制器編寫單元測試。
這就是我做,以避免我的全部啓動順序:
編輯方案
runningTests
設置爲YES
編輯應用程序委託
以下內容添加到-application:didFinishLaunchingWithOptions:
只要是有意義的:
#if DEBUG
if (getenv("runningTests"))
return YES;
#endif
執行相同的-applicationDidBecomeActive:
而只是return
。
更新:我改變了我的方法。請參閱How to Easily Switch Your App Delegate for Testing。
在之前的回答中指出,邏輯測試對於這種情況是正確的。我在使用XCode 4.3.2(4E2002)進行邏輯測試方面非常艱難。看着Apple's sample unit test project幫助我理解了如何以明確的分離方式做到這一點。在那個例子中,邏輯測試來自庫目標的測試文件,而不是應用程序目標。該模型被封裝成一個庫,然後與主要目標和邏輯測試目標鏈接。應用程序目標僅包含視圖和控制器。
基於這種模式,這是我做了讓我的邏輯測試正常工作。創建一個新的目標(Cocoa Touch靜態庫),並將所有文件移動到這個新目標進行邏輯測試(通常是所有模型)。 「Build Phases」設置在「Link Binary With Libraries」您的應用程序目標和邏輯測試目標中添加此新庫。
我可以想象這些說明有點混亂。如果你剖析上面提到的示例項目,你會得到一個更好的主意。
注意,在Xcode的5
未經測試我使用@喬恩 - 裏德的答案時,卻發現Xcode中加環境變量XcodeProjects的xcuserstated部分,而這些用戶特定的,而不是通常承諾存儲庫。因此,我調酒我的AppDelegate覆蓋其裝載:
@implementation MyAppDelegate (Testing)
+ (void)initialize {
SEL new = @selector(application:didFinishLaunchingWithOptions:);
SEL orig = @selector(swizzled_application:didFinishLaunchingWithOptions:);
Class c = [self class];
Method origMethod = class_getInstanceMethod(c, orig);
Method newMethod = class_getInstanceMethod(c, new);
if (class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) {
class_replaceMethod(c, new, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
} else {
method_exchangeImplementations(origMethod, newMethod);
}
}
- (BOOL)swizzled_application:(id)app didFinishLaunchingWithOptions:(id)opts {
return YES;
}
@end
注意的是,以下是簡單的和仍然有效,但我不知道它是可靠的:
@implementation MyAppDelegate (Testing)
- (BOOL)application:(id)app didFinishLaunchingWithOptions:(id)opts {
return YES;
}
@end
這工作,因爲類別動態加載組件中的方法(如測試包)優先。雖然Swizzling感覺更安全。
我應該在哪裏放置這段代碼?我目前的目標根本沒有AppDelegate。如果我將它添加到我的UnitTest目標中,它不會改變任何內容。 (我正在使用XCode 4.6) –
你把它放在測試目標中,並且你將'MyAppDelegate'重命名爲你的AppDelegate的類名在你的主目標中。您的測試目標沒有應用程序委託,但這就是這個問題的要點,來自主目標的應用程序委託*仍然*執行。 – mxcl
在Xcode 5中不起作用xcunit測試 – user170317
感謝您的提示!使用和完美的工作。 – yonel
我想這隻適用於加載他們的GUI在應用程序:didFinishLaunchingWithOptions:的應用程序。如果您正在構建使用故事板的應用程序,該怎麼辦? – ABeanSits
我應該在哪裏放這段代碼?我目前的目標根本沒有AppDelegate。如果我將它添加到我的UnitTest目標中,它不會改變任何內容。 (我正在使用XCode 4.6) –