web-dev-qa-db-ja.com

NSURLとXCTestを使用したテストバンドルのファイルパス

TDDと新しいXCTestフレームワークを使用してiOSアプリを作成しようとしています。私のメソッドの1つは、インターネットからファイルを取得し(NSURLオブジェクトを指定)、ユーザーのドキュメントに保存します。メソッドのシグネチャは次のようになります。

- (void) fetchAndStoreImage:(NSURL *)imageUrl

インターネットへの接続がない場合に失敗しないように、このメソッドのテストを作成しようとしています。私のアプローチ(以前の question から取った)は、ローカルファイルシステムのイメージへのNSURLを使用してメソッドを呼び出すことです。

単体テストが有効になっている新しいプロジェクトが作成されると、Testsディレクトリには「Supporting Files」という名前のサブディレクトリがあります。私のテスト画像はそこに行くべきだと思います。私の質問は、テスト画像をアプリケーションにバンドルしたくないので、このディレクトリ内の画像を指すNSURLオブジェクトをどのように取得できるかです。どんな助けも大歓迎です。

68

実際、[NSBundle mainBundle] UnitTestの実行時はnotアプリのパスですが、/ Developer/usr/binであるため、これは機能しません。

単体テストでリソースを取得する方法は次のとおりです。 OCUnit&NSBundle

要するに、使用してください:

[[NSBundle bundleForClass:[self class]] resourcePath]

またはあなたの場合:

[[NSBundle bundleForClass:[self class]] resourceURL]
121
Ben Clayton

スイフト2:

let testBundle = NSBundle(forClass: self.dynamicType)
let fileURL = testBundle.URLForResource("imageName", withExtension: "png")
XCTAssertNotNil(fileURL)

Swift 3、4:

let testBundle = Bundle(for: type(of: self))
let fileURL = testBundle.url(forResource: "imageName", withExtension: "png")
XCTAssertNotNil(filePath)

バンドルは、構成のメインパスとテストパスを検出する方法を提供します。

@testable import Example

class ExampleTests: XCTestCase {

    func testExample() {
        let bundleMain = Bundle.main
        let bundleDoingTest = Bundle(for: type(of: self ))
        let bundleBeingTested = Bundle(identifier: "com.example.Example")!

        print("bundleMain.bundlePath : \(bundleMain.bundlePath)")
        // …/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Xcode/Agents
        print("bundleDoingTest.bundlePath : \(bundleDoingTest.bundlePath)")
        // …/PATH/TO/Debug/ExampleTests.xctest
        print("bundleBeingTested.bundlePath : \(bundleBeingTested.bundlePath)")
        // …/PATH/TO/Debug/Example.app

        print("bundleMain = " + bundleMain.description) // Xcode Test Agent
        print("bundleDoingTest = " + bundleDoingTest.description) // Test Case Bundle
        print("bundleUnderTest = " + bundleBeingTested.description) // App Bundle

Xcode 6 | 7 | 8 URLはDeveloper/Xcode/DerivedDataのようなものになります...

file:///Users/
  UserName/
    Library/
      Developer/
        Xcode/
          DerivedData/
            App-qwertyuiop.../
              Build/
                Products/
                  Debug-iphonesimulator/
                    AppTests.xctest/
                      imageName.png

... Developer/CoreSimulator/Devices URLとは別のもの

file:///Users/
  UserName/
    Library/
    Developer/
      CoreSimulator/
        Devices/
          _UUID_/
            data/
              Containers/
                Bundle/
                  Application/
                    _UUID_/
                      App.app/

また、デフォルトで単体テスト実行可能ファイルがアプリケーションコードにリンクされていることに注意してください。ただし、単体テストコードには、テストバンドルのみにターゲットメンバーシップが含まれている必要があります。アプリケーションコードには、アプリケーションバンドルにターゲットメンバーシップのみが含まれている必要があります。実行時、単体テストのターゲットバンドルは 実行のためにアプリケーションバンドルに挿入されます

Swift Package Manager(SPM)4:

let testBundle = Bundle(for: type(of: self)) 
print("testBundle.bundlePath = \(testBundle.bundlePath) ")

注:デフォルトでは、コマンドラインSwift testMyProjectPackageTests.xctestテストバンドルを作成します。そして、Swift package generate-xcodeprojMyProjectTests.xctestテストバンドルを作成します。これらの異なるテストバンドルには、異なるパスがあります。 また、異なるテストバンドルには、いくつかの内部ディレクトリ構造とコンテンツの違いがあります。

いずれの場合も、.bundlePathおよび.bundleURLは、macOSで現在実行されているテストバンドルのパスを返します。ただし、Bundleは現在Ubuntuには実装されていません。

また、コマンドラインSwift buildおよびSwift testは現在、リソースをコピーするメカニズムを提供していません。

ただし、多少の努力を払えば、macOS Xcode、macOSコマンドライン、Ubuntuコマンドライン環境のリソースでSwift Package Mangerを使用するためのプロセスを設定できます。1つの例を見つけることができます。ここ: 4.4'2 SW Dev SwiftリソースQrefを使用したパッケージマネージャー(SPM)

Swift Package Manager(SPM)4.2

Swift Package Manager PackageDescription 4.2 は、 ローカル依存関係 のサポートを導入します。

ローカル依存関係は、パスを使用して直接参照できるディスク上のパッケージです。ローカル依存関係はルートパッケージでのみ許可され、パッケージグラフ内の同じ名前のすべての依存関係をオーバーライドします。

注:SPM 4.2では次のようなことが可能になるはずだと予想していますが、まだテストしていません。

// Swift-tools-version:4.2
import PackageDescription

let package = Package(
    name: "MyPackageTestResources",
    dependencies: [
        .package(path: "../test-resources"),
    ],
    targets: [
        // ...
        .testTarget(
            name: "MyPackageTests",
            dependencies: ["MyPackage", "MyPackageTestResources"]
        ),
    ]
)
40
l --marc l

正解に追加するために、これはUnitTests/Supporting Files内のファイルのfilePathを取得する方法の例です。

NSString *filePath = [[[NSBundle bundleForClass:[self class]] resourcePath] stringByAppendingPathComponent:@"YourFileName.json"];
XCTAssertNotNil(filePath);

これはおそらく誰かに役立つでしょう。

13
wzbozon
  1. 任意のターゲットのようにバンドルファイルを参照できます。
  2. (テストターゲットの)バンドルリソースのコピービルドフェーズでファイルがコピーされているかどうかを確認します。
  3. ローカルファイルにアクセスするには:

    NSURL*imageUrl=[[NSBundle mainBundle]URLForResource:@"imageName" withExtension:@"png"];
    

次を使用して非同期アクセスを行い、応答を待つことができます: https://github.com/travisjeffery/TRVSMonitor

追加した場合:dataset1.jsonテスト対象(2)内:

NSString *p=[[NSBundle mainBundle] pathForResource:@"dataset1" ofType:@"json"];
NSLog(@"%@",p);

2013-10-29 15:49:30.547 PlayerSample [13771:70b] WT(0):/ Users/bpds/Library/Application Support/iPhone Simulator/7.0/Applications/7F78780B-684A-40E0-AA35-A3B5D8AA9DBD/PlayerSample。 app.app/dataset1.json

3
bpds

受け入れられた回答に基づくSwiftバージョン:

let url = URL(fileURLWithPath: Bundle(for: type(of: self)).path(forResource: "my", ofType: "json") ?? "TODO: Proper checking for file")
1
superarts.org

私が直面していた問題は、アプリケーションコードがbundleIdentifierなどのメインバンドルにアクセスしようとしており、メインバンドルがユニットテストプロジェクトではなかったため、nilが返されることでした。

Swift 3.0.1とObjective-Cの両方で機能するこのハックは、NSBundleにObjective-Cカテゴリを作成し、単体テストプロジェクトに含めることです。このカテゴリはロードされ、アプリケーションコードがメインバンドルを要求すると、カテゴリは単体テストバンドルを返します。

@interface NSBundle (MainBundle)

+(NSBundle *)mainBundle;

@end

@implementation NSBundle (Main)

#pragma clang diagnostic Push
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
+(NSBundle *)mainBundle
{
    return [NSBundle bundleForClass:[SomeUnitTest class]];
}
#pragma clang diagnostic pop

@end
1
odyth

Swiftこのバージョン、Xcode 7、iOS 9など).

let testBundle = NSBundle(forClass: self.dynamicType)
let path = testBundle.pathForResource("someImage", ofType: "jpg")
XCTAssertNotNil(path)

注:テストイメージにはsomeImage.jpgを含める必要があります。

0
Dan Rosenstark