Skip to content

Commit 24f9777

Browse files
committed
Updated unit tests
1 parent a0d8f56 commit 24f9777

11 files changed

Lines changed: 310 additions & 172 deletions

File tree

CoreDataMigration-Example.xcodeproj/project.pbxproj

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
43370DB31F66E830006188EC /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 43370D781F66E74A006188EC /* LaunchScreen.storyboard */; };
2525
43370DB41F66E832006188EC /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 43370D7A1F66E74A006188EC /* Main.storyboard */; };
2626
43370DBE1F66F0DF006188EC /* CoreDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43370DBB1F66F0C0006188EC /* CoreDataManager.swift */; };
27+
4343875D2F7963FF0041D11F /* CoreDataVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4343875C2F7963FF0041D11F /* CoreDataVersion.swift */; };
2728
4345D4EE1F67E0FE00027D11 /* UIColor+Hex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4345D4ED1F67E0FE00027D11 /* UIColor+Hex.swift */; };
2829
4345D4F01F67E10700027D11 /* UIColor+Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4345D4EF1F67E10700027D11 /* UIColor+Random.swift */; };
2930
4345D4F51F67E1FC00027D11 /* CGFloat+Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4345D4F41F67E1FC00027D11 /* CGFloat+Random.swift */; };
@@ -38,7 +39,8 @@
3839
434FE74C2F795ACA00359208 /* CoreDataMigratorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434FE7422F795ACA00359208 /* CoreDataMigratorTests.swift */; };
3940
434FE74D2F795ADC00359208 /* TestingAppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434FE7372F795ACA00359208 /* TestingAppDelegate.swift */; };
4041
434FE7502F795AFD00359208 /* CoreDataMigratorMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434FE74E2F795AFD00359208 /* CoreDataMigratorMock.swift */; };
41-
434FE7532F795B5400359208 /* CoreDataMigrationModelSpy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434FE7512F795B5400359208 /* CoreDataMigrationModelSpy.swift */; };
42+
434FE7532F795B5400359208 /* StubCoreDataMigrationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434FE7512F795B5400359208 /* StubCoreDataMigrationModel.swift */; };
43+
43EC64232F79925F0055607E /* CoreDataVersionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43EC64222F79925E0055607E /* CoreDataVersionTests.swift */; };
4244
/* End PBXBuildFile section */
4345

4446
/* Begin PBXContainerItemProxy section */
@@ -74,6 +76,7 @@
7476
43370D791F66E74A006188EC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
7577
43370D7B1F66E74A006188EC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
7678
43370DBB1F66F0C0006188EC /* CoreDataManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataManager.swift; sourceTree = "<group>"; };
79+
4343875C2F7963FF0041D11F /* CoreDataVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataVersion.swift; sourceTree = "<group>"; };
7780
4345D4ED1F67E0FE00027D11 /* UIColor+Hex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Hex.swift"; sourceTree = "<group>"; };
7881
4345D4EF1F67E10700027D11 /* UIColor+Random.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Random.swift"; sourceTree = "<group>"; };
7982
4345D4F41F67E1FC00027D11 /* CGFloat+Random.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CGFloat+Random.swift"; sourceTree = "<group>"; };
@@ -87,10 +90,11 @@
8790
434FE7412F795ACA00359208 /* CoreDataMigrationModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataMigrationModelTests.swift; sourceTree = "<group>"; };
8891
434FE7422F795ACA00359208 /* CoreDataMigratorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataMigratorTests.swift; sourceTree = "<group>"; };
8992
434FE74E2F795AFD00359208 /* CoreDataMigratorMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataMigratorMock.swift; sourceTree = "<group>"; };
90-
434FE7512F795B5400359208 /* CoreDataMigrationModelSpy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataMigrationModelSpy.swift; sourceTree = "<group>"; };
93+
434FE7512F795B5400359208 /* StubCoreDataMigrationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StubCoreDataMigrationModel.swift; sourceTree = "<group>"; };
9194
43AB8AE51F66E6A5003153B3 /* CoreDataMigration-Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "CoreDataMigration-Example.app"; sourceTree = BUILT_PRODUCTS_DIR; };
9295
43AB8AFC1F66E6A5003153B3 /* CoreDataMigration-ExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "CoreDataMigration-ExampleTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
9396
43AB8B021F66E6A5003153B3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
97+
43EC64222F79925E0055607E /* CoreDataVersionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataVersionTests.swift; sourceTree = "<group>"; };
9498
43FBB4421F6C16FB0090C536 /* CoreDataMigration-ExampleTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "CoreDataMigration-ExampleTests-Bridging-Header.h"; sourceTree = "<group>"; };
9599
/* End PBXFileReference section */
96100

@@ -118,6 +122,7 @@
118122
431DCEB01F67EE2600CF6316 /* CoreDataMigrationModel.swift */,
119123
431DCEB11F67EE2600CF6316 /* CoreDataMigrationStep.swift */,
120124
431DCEB21F67EE2600CF6316 /* CoreDataMigrator.swift */,
125+
4343875C2F7963FF0041D11F /* CoreDataVersion.swift */,
121126
431DCEB31F67EE2600CF6316 /* Mappings */,
122127
431DCED01F68156B00CF6316 /* Policies */,
123128
);
@@ -253,7 +258,7 @@
253258
children = (
254259
434FE7372F795ACA00359208 /* TestingAppDelegate.swift */,
255260
434FE74E2F795AFD00359208 /* CoreDataMigratorMock.swift */,
256-
434FE7512F795B5400359208 /* CoreDataMigrationModelSpy.swift */,
261+
434FE7512F795B5400359208 /* StubCoreDataMigrationModel.swift */,
257262
);
258263
path = Doubles;
259264
sourceTree = "<group>";
@@ -284,6 +289,7 @@
284289
434FE7402F795ACA00359208 /* CoreDataManagerTests.swift */,
285290
434FE7412F795ACA00359208 /* CoreDataMigrationModelTests.swift */,
286291
434FE7422F795ACA00359208 /* CoreDataMigratorTests.swift */,
292+
43EC64222F79925E0055607E /* CoreDataVersionTests.swift */,
287293
);
288294
path = Tests;
289295
sourceTree = "<group>";
@@ -448,6 +454,7 @@
448454
431DCECB1F67F93000CF6316 /* AppLoadingViewController.swift in Sources */,
449455
431DCED61F68315900CF6316 /* Migration2to3.xcmappingmodel in Sources */,
450456
4345D4F51F67E1FC00027D11 /* CGFloat+Random.swift in Sources */,
457+
4343875D2F7963FF0041D11F /* CoreDataVersion.swift in Sources */,
451458
432EA5591F6C552800EFE008 /* NSPersistentStoreCoordinator+SQLite.swift in Sources */,
452459
4345D4F01F67E10700027D11 /* UIColor+Random.swift in Sources */,
453460
4345D4EE1F67E0FE00027D11 /* UIColor+Hex.swift in Sources */,
@@ -470,8 +477,9 @@
470477
434FE7502F795AFD00359208 /* CoreDataMigratorMock.swift in Sources */,
471478
434FE74A2F795ACA00359208 /* TestingAppDelegate.swift in Sources */,
472479
434FE74B2F795ACA00359208 /* CoreDataManagerTests.swift in Sources */,
473-
434FE7532F795B5400359208 /* CoreDataMigrationModelSpy.swift in Sources */,
480+
434FE7532F795B5400359208 /* StubCoreDataMigrationModel.swift in Sources */,
474481
434FE74C2F795ACA00359208 /* CoreDataMigratorTests.swift in Sources */,
482+
43EC64232F79925F0055607E /* CoreDataVersionTests.swift in Sources */,
475483
);
476484
runOnlyForDeploymentPostprocessing = 0;
477485
};

CoreDataMigration-Example/CoreData/Migration/CoreDataMigrationModel.swift

Lines changed: 3 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -9,44 +9,7 @@
99
import Foundation
1010
import CoreData
1111

12-
enum CoreDataVersion: Int {
13-
case version1 = 1
14-
case version2
15-
case version3
16-
case version4
17-
18-
// MARK: - Accessors
19-
20-
var name: String {
21-
if rawValue == 1 {
22-
return "CoreDataMigration_Example"
23-
} else {
24-
return "CoreDataMigration_Example \(rawValue)"
25-
}
26-
}
27-
28-
static var all: [CoreDataVersion] {
29-
var versions = [CoreDataVersion]()
30-
31-
for rawVersionValue in 1...1000 { // A bit of a hack here to avoid manual mapping
32-
if let version = CoreDataVersion(rawValue: rawVersionValue) {
33-
versions.append(version)
34-
continue
35-
}
36-
37-
break
38-
}
39-
40-
return versions.reversed()
41-
}
42-
43-
static var latest: CoreDataVersion {
44-
return all.first!
45-
}
46-
}
47-
4812
class CoreDataMigrationModel {
49-
5013
let version: CoreDataVersion
5114

5215
var modelBundle: Bundle {
@@ -60,7 +23,7 @@ class CoreDataMigrationModel {
6023
static var all: [CoreDataMigrationModel] {
6124
var migrationModels = [CoreDataMigrationModel]()
6225

63-
for version in CoreDataVersion.all {
26+
for version in CoreDataVersion.allCases {
6427
migrationModels.append(CoreDataMigrationModel(version: version))
6528
}
6629

@@ -93,8 +56,8 @@ class CoreDataMigrationModel {
9356
// MARK: - Model
9457

9558
func managedObjectModel() -> NSManagedObjectModel {
96-
let omoURL = modelBundle.url(forResource: version.name, withExtension: "omo", subdirectory: modelDirectoryName) // optimized model file
97-
let momURL = modelBundle.url(forResource: version.name, withExtension: "mom", subdirectory: modelDirectoryName)
59+
let omoURL = modelBundle.url(forResource: version.rawValue, withExtension: "omo", subdirectory: modelDirectoryName) // optimized model file
60+
let momURL = modelBundle.url(forResource: version.rawValue, withExtension: "mom", subdirectory: modelDirectoryName)
9861

9962
guard let url = omoURL ?? momURL else {
10063
fatalError("Unable to find model in bundle")

CoreDataMigration-Example/CoreData/Migration/CoreDataMigrationStep.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import CoreData
1010

1111
struct CoreDataMigrationStep {
12-
1312
let source: NSManagedObjectModel
1413
let destination: NSManagedObjectModel
1514
let mapping: NSMappingModel
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//
2+
// CoreDataVersion.swift
3+
// CoreDataMigration-Example
4+
//
5+
// Created by William Boles on 29/03/2026.
6+
// Copyright © 2026 William Boles. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
enum CoreDataVersion: String, CaseIterable {
12+
case version1 = "CoreDataMigration_Example"
13+
case version2 = "CoreDataMigration_Example 2"
14+
case version3 = "CoreDataMigration_Example 3"
15+
case version4 = "CoreDataMigration_Example 4"
16+
17+
static var latest: CoreDataVersion {
18+
return allCases.last!
19+
}
20+
}

CoreDataMigration-ExampleTests/Doubles/CoreDataMigrationModelSpy.swift

Lines changed: 0 additions & 30 deletions
This file was deleted.

CoreDataMigration-ExampleTests/Doubles/CoreDataMigratorMock.swift

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,22 @@ import CoreData
1212
@testable import CoreDataMigration_Example
1313

1414
class CoreDataMigratorMock: CoreDataMigrator {
15+
enum Event {
16+
case requiresMigration(URL, CoreDataMigrationModel)
17+
case migrateStore(URL)
18+
}
1519

16-
var requiresMigrationWasCalled = false
17-
var migrateStoreWasCalled = false
20+
private(set) var events: [Event] = []
1821

19-
var requiresMigrationToBeReturned = false
22+
var requiresMigrationToBeReturned: Bool!
2023

2124
override func requiresMigration(at: URL, currentMigrationModel: CoreDataMigrationModel = CoreDataMigrationModel.current) -> Bool {
22-
requiresMigrationWasCalled = true
25+
events.append(.requiresMigration(at, currentMigrationModel))
2326

2427
return requiresMigrationToBeReturned
2528
}
2629

2730
override func migrateStore(at: URL) {
28-
migrateStoreWasCalled = true
31+
events.append(.migrateStore(at))
2932
}
3033
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//
2+
// CoreDataMigrationModelSpy.swift
3+
// CoreDataMigration-ExampleTests
4+
//
5+
// Created by William Boles on 29/03/2026.
6+
// Copyright © 2026 William Boles. All rights reserved.
7+
//
8+
9+
import Foundation
10+
import CoreData
11+
12+
@testable import CoreDataMigration_Example
13+
14+
class StubCoreDataMigrationModel: CoreDataMigrationModel {
15+
enum Event {
16+
case inferredMappingModel(CoreDataMigrationModel)
17+
case customMappingModel(CoreDataMigrationModel)
18+
}
19+
20+
var inferredMappingModel: NSMappingModel!
21+
var customMappingModelReturnValue: NSMappingModel?
22+
23+
private(set) var events: [Event] = []
24+
25+
override func inferredMappingModel(to nextVersion: CoreDataMigrationModel) -> NSMappingModel {
26+
events.append(.inferredMappingModel(nextVersion))
27+
28+
return inferredMappingModel
29+
}
30+
31+
override func customMappingModel(to nextVersion: CoreDataMigrationModel) -> NSMappingModel? {
32+
events.append(.customMappingModel(nextVersion))
33+
34+
return customMappingModelReturnValue
35+
}
36+
}

CoreDataMigration-ExampleTests/Tests/CoreDataManagerTests.swift

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -33,52 +33,57 @@ class CoreDataManagerTests: XCTestCase {
3333

3434
// MARK: - Setup
3535

36-
func test_setup_loadsStore() {
37-
let promise = expectation(description: "calls back")
36+
func test_givenNoMigrationRequired_whenSetup_thenLoadsStore() {
37+
migrator.requiresMigrationToBeReturned = false
38+
39+
let expectation = expectation(description: "calls back")
3840
sut.setup {
3941
XCTAssertTrue(self.sut.persistentContainer.persistentStoreCoordinator.persistentStores.count > 0)
4042

41-
promise.fulfill()
43+
expectation.fulfill()
4244
}
4345

44-
waitForExpectations(timeout: 10) { error in
45-
if let error = error {
46-
print("Timed out: \(String(describing: error))")
47-
}
48-
}
46+
waitForExpectations(timeout: 10)
4947
}
5048

51-
func test_setup_checksIfMigrationRequired() {
52-
let promise = expectation(description: "calls back")
49+
func test_givenNoMigrationRequired_whenSetup_thenChecksIfMigrationRequiredButDoesNotMigrate() {
50+
migrator.requiresMigrationToBeReturned = false
51+
52+
let expectation = expectation(description: "calls back")
5353
sut.setup {
54-
XCTAssertTrue(self.migrator.requiresMigrationWasCalled)
55-
XCTAssertFalse(self.migrator.migrateStoreWasCalled)
54+
let hasRequiresMigrationEvent = self.migrator.events.contains { event in
55+
if case .requiresMigration = event { return true }
56+
return false
57+
}
58+
let hasMigrateStoreEvent = self.migrator.events.contains { event in
59+
if case .migrateStore = event { return true }
60+
return false
61+
}
62+
63+
XCTAssertTrue(hasRequiresMigrationEvent)
64+
XCTAssertFalse(hasMigrateStoreEvent)
5665

57-
promise.fulfill()
66+
expectation.fulfill()
5867
}
5968

60-
waitForExpectations(timeout: 10) { error in
61-
if let error = error {
62-
print("Timed out: \(String(describing: error))")
63-
}
64-
}
69+
waitForExpectations(timeout: 10)
6570
}
6671

67-
func test_setup_migrate() {
72+
func test_givenMigrationRequired_whenSetup_thenMigratesStore() {
6873
migrator.requiresMigrationToBeReturned = true
6974

70-
let promise = expectation(description: "calls back")
75+
let expectation = expectation(description: "calls back")
7176
sut.setup {
72-
XCTAssertTrue(self.migrator.migrateStoreWasCalled)
77+
let hasMigrateStoreEvent = self.migrator.events.contains { event in
78+
if case .migrateStore = event { return true }
79+
return false
80+
}
81+
82+
XCTAssertTrue(hasMigrateStoreEvent)
7383

74-
promise.fulfill()
84+
expectation.fulfill()
7585
}
7686

77-
waitForExpectations(timeout: 10) { error in
78-
if let error = error {
79-
print("Timed out: \(String(describing: error))")
80-
}
81-
}
87+
waitForExpectations(timeout: 10)
8288
}
83-
8489
}

0 commit comments

Comments
 (0)