NSURL, чтобы указать путь в тестовом комплекте с помощью XCTest
Я пытаюсь написать приложение iOS, используя TDD и новую инфраструктуру XCTest. Один из моих методов извлекает файл из Интернета (с учетом объекта NSURL) и сохраняет его в пользовательских документах. Подпись метода аналогична:
- (void) fetchAndStoreImage:(NSURL *)imageUrl
Я пытаюсь написать тест для этого метода таким образом, чтобы он не прерывался, если нет подключения к Интернету. Мой подход (взятый из предыдущего question) заключается в вызове метода с использованием NSURL для изображения в локальной файловой системе.
Когда новый проект с включенными модульными испытаниями создан, в каталоге Tests есть подкаталог с именем "Supporting Files". Я предполагаю, что это то, где мои тестовые изображения должны идти. Мой вопрос в том, как я могу получить объект NSURL, который указывает на изображение в этом каталоге, так как я бы не хотел, чтобы тестовые изображения были связаны с приложением. Любая помощь приветствуется.
Ответы
Ответ 1
Фактически, [NSBundle mainBundle]
при запуске UnitTest - это не путь вашего приложения, а /Developer/usr/bin, так что это не будет работать.
Способ получить ресурсы в модульном тесте здесь: OCUnit & NSBundle
Короче говоря, используйте:
[[NSBundle bundleForClass:[self class]] resourcePath]
или в вашем случае:
[[NSBundle bundleForClass:[self class]] resourceURL]
Ответ 2
Свифт 2:
let testBundle = NSBundle(forClass: self.dynamicType)
let fileURL = testBundle.URLForResource("imageName", withExtension: "png")
XCTAssertNotNil(fileURL)
Свифт 3, 4:
let testBundle = Bundle(for: type(of: self))
let fileURL = testBundle.url(forResource: "imageName", withExtension: "png")
XCTAssertNotNil(filePath)
Bundle предоставляет способы обнаружения основных и тестовых путей для вашей конфигурации:
@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
URL Xcode 6 | 7 | 8 будет в Developer/Xcode/DerivedData
что-то вроде...
file:///Users/
UserName/
Library/
Developer/
Xcode/
DerivedData/
App-qwertyuiop.../
Build/
Products/
Debug-iphonesimulator/
AppTests.xctest/
imageName.png
... который является отдельным от URL Developer/CoreSimulator/Devices
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 test
командной строки создает тестовый пакет MyProjectPackageTests.xctest
. Причем, swift package generate-xcodeproj
создаст MyProjectTests.xctest
тестовый пакет. Эти разные тестовые пакеты имеют разные пути. Кроме того, разные тестовые пакеты могут иметь некоторые внутренние структуры каталогов и различия в содержимом.
В любом случае .bundlePath
и .bundleURL
будут возвращать путь тестового пакета, который в данный момент выполняется на macOS. Однако Bundle
в настоящее время не реализован для Ubuntu.
Кроме того, в командной строке swift build
и swift test
настоящее время не предусмотрен механизм копирования ресурсов.
Однако, приложив некоторые усилия, можно настроить процессы для использования Swift Package Manger с ресурсами в средах macOS Xcode, macOS и Ubuntu. Один пример можно найти здесь: 004.4'2 SW Dev Swift Package Manager (SPM) с ресурсами Qref
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"]
),
]
)
Ответ 3
Чтобы добавить правильный ответ, это пример того, как получить filePath для файла в вашем UnitTests/Supporting Files:
NSString *filePath = [[[NSBundle bundleForClass:[self class]] resourcePath] stringByAppendingPathComponent:@"YourFileName.json"];
XCTAssertNotNil(filePath);
Это, вероятно, будет полезно для кого-то.
Ответ 4
- Вы можете ссылаться на файлы комплекта, как в любой цели.
- Проверьте, копируется ли файл в фазе сборки Copy Bundle Resources (вашей тестовой цели)
-
Для доступа к локальному файлу:
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/Поддержка приложений /iPhone Simulator/7.0/Applications/7F78780B-684A-40E0-AA35-A3B5D8AA9DBD/PlayerSample. app.app/dataset1.json
Ответ 5
Проблема, с которой я столкнулся, заключалась в том, что код приложения пытался получить доступ к основному набору для таких вещей, как bundleIdentifier, и поскольку основной пакет не был моим проектом unit test, он возвращал бы нуль.
Взлом вокруг этого, который работает как в Swift 3.0.1, так и в Objective-C, заключается в создании категории Objective-C в NSBundle и включении его в ваш проект unit test. Вам не нужен мостовой заголовок или что-то еще. Эта категория загрузится, и теперь, когда код приложения запрашивает основной пакет, ваша категория вернет пакет unit test.
@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
Ответ 6
Здесь версия Swift, Xcode 7, iOS 9 и т.д.
let testBundle = NSBundle(forClass: self.dynamicType)
let path = testBundle.pathForResource("someImage", ofType: "jpg")
XCTAssertNotNil(path)
Примечание: someImage.jpg должен быть включен в вашу тестовую цель.
Ответ 7
Версия Swift
на основе принятого ответа:
let url = URL(fileURLWithPath: Bundle(for: type(of: self)).path(forResource: "my", ofType: "json") ?? "TODO: Proper checking for file")