#unit-testing #core-data
#модульное тестирование #core-data
Вопрос:
С новым шаблоном Swift App Xcode я вижу, что PersistenceController
структура была добавлена с экземпляром shared
и preview
, который служит основным стеком данных. Насколько я понимаю, preview
экземпляр предназначен для предварительного просмотра SwiftUI.
Если у меня есть класс обслуживания, который использует экземпляр моего основного стека данных, должен ли я использовать preview
экземпляр как часть моих модульных тестов? Или я должен создать какой-то шпион / подделку для перехода в класс обслуживания, который я тестирую?
В целом, каковы наилучшие методы тестирования классов, использующих основные данные?
Ответ №1:
Я также просто изучаю это. Я не нашел лучшей практики. Итак, я подведу итог тому, что я делаю. PersistenceController — хороший шаблон.
Статический предварительный просмотр var позволяет создать другое хранилище и добавить в него некоторые объекты, например
static var preview: PersistenceController = {
let result = PersistenceController(inMemory: true)
let viewContext = result.container.viewContext
// this is the part where you can add mock data
for _ in 0..<10 {
let newItem = Note(context: viewContext)
newItem.creationDate = Date()
}
do {
try viewContext.save()
} catch {
let nsError = error as NSError
fatalError("Unresolved error (nsError), (nsError.userInfo)")
}
return result
}()
Для модульных тестов мы хотели бы начать с пустого хранилища, поэтому я просто добавил еще одну переменную в PersistenceController
static let unitTest: PersistenceController = {
let result = PersistenceController(inMemory: true)
//empty store
return result
}()
Это делает мой модульный тест похожим
class TestCoreDataStack: XCTestCase {
var coreDataStack: PersistenceController!
override func setUp() {
super.setUp()
coreDataStack = PersistenceController.unitTest
}
override func tearDown() {
super.tearDown()
//called after the invocation of each test method in the class.
// I am deleted all notes to start fresh for the next test
UnitTestHelpers.deleteAllNotes(container: coreDataStack.container)
coreDataStack = nil
}
func testAddNote() {
let context = coreDataStack.container.viewContext
let title = "my new title"
let note = Note(title: title, context: context)
XCTAssertNotNil(note, "note should not be nil")
XCTAssertTrue(note.title == title)
XCTAssertNotNil(note.creationDate, "notes date should not be nil")
} }
Комментарии:
1. Мне понравилось это решение, но я обнаружил, что у меня возникли проблемы с контроллером сохраняемости модульных тестов, который не инициализировался повторно между тестами, и я не хотел каждый раз вручную удалять все. В конце я просто вызываю
coreDataStack = PersistenceController(inMemory: true)
в настройках, и это работает до сих пор.2. @kprater Я попробовал аналогичную настройку, но затем я получаю
Multiple NSEntityDescriptions claim the NSManagedObject subclass
предупреждение иFailed to find a unique match for an NSEntityDescription to a managed object subclass
ошибку, поскольку как статическийshared
(из инициализации приложения), так и статическийtest
инициализируются при запуске модульного теста.