Skip to content

Commit 6dcf350

Browse files
committed
Add CoreDataXCTestCase.verify helper to more thoroughly check the store for an object after creation or mutation.
bugfix/create-returns-items-with-temporary-objectids
1 parent cd59a8e commit 6dcf350

3 files changed

Lines changed: 63 additions & 15 deletions

File tree

Tests/CoreDataRepositoryTests/BatchRepositoryTests.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ final class BatchRepositoryTests: CoreDataXCTestCase {
116116
XCTAssertEqual(result.success.count, newMovies.count)
117117
XCTAssertEqual(result.failed.count, 0)
118118

119+
for movie in result.success {
120+
try await verify(movie)
121+
}
122+
119123
try await repositoryContext().perform {
120124
let data = try self.repositoryContext().fetch(fetchRequest)
121125
XCTAssertEqual(

Tests/CoreDataRepositoryTests/CRUDRepositoryTests.swift

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,16 @@ final class CRUDRepositoryTests: CoreDataXCTestCase {
1616
func testCreateSuccess() async throws {
1717
let movie = Movie(id: UUID(), title: "Create Success", releaseDate: Date(), boxOffice: 100)
1818
let result: Result<Movie, CoreDataRepositoryError> = try await repository().create(movie)
19-
guard case var .success(resultMovie) = result else {
19+
guard case let .success(resultMovie) = result else {
2020
XCTFail("Not expecting a failed result")
2121
return
2222
}
23+
var tempResultMovie = resultMovie
24+
XCTAssertNotNil(tempResultMovie.url)
25+
tempResultMovie.url = nil
26+
XCTAssertNoDifference(tempResultMovie, movie)
2327

24-
XCTAssertNotNil(resultMovie.url)
25-
resultMovie.url = nil
26-
let diff = CustomDump.diff(resultMovie, movie)
27-
XCTAssertNil(diff)
28+
try await verify(resultMovie)
2829
}
2930

3031
func testReadSuccess() async throws {
@@ -39,15 +40,18 @@ final class CRUDRepositoryTests: CoreDataXCTestCase {
3940
let result: Result<Movie, CoreDataRepositoryError> = try await repository()
4041
.read(try XCTUnwrap(createdMovie.url))
4142

42-
guard case var .success(resultMovie) = result else {
43+
guard case let .success(resultMovie) = result else {
4344
XCTFail("Not expecting a failed result")
4445
return
4546
}
4647

47-
XCTAssertNotNil(resultMovie.url)
48-
resultMovie.url = nil
49-
let diff = CustomDump.diff(resultMovie, movie)
50-
XCTAssertNil(diff)
48+
var tempResultMovie = resultMovie
49+
50+
XCTAssertNotNil(tempResultMovie.url)
51+
tempResultMovie.url = nil
52+
XCTAssertNoDifference(tempResultMovie, movie)
53+
54+
try await verify(resultMovie)
5155
}
5256

5357
func testReadFailure() async throws {
@@ -91,15 +95,18 @@ final class CRUDRepositoryTests: CoreDataXCTestCase {
9195
let result: Result<Movie, CoreDataRepositoryError> = try await repository()
9296
.update(try XCTUnwrap(createdMovie.url), with: movie)
9397

94-
guard case var .success(resultMovie) = result else {
98+
guard case let .success(resultMovie) = result else {
9599
XCTFail("Not expecting a failed result")
96100
return
97101
}
98102

99-
XCTAssertNotNil(resultMovie.url)
100-
resultMovie.url = nil
101-
let diff = CustomDump.diff(resultMovie, movie)
102-
XCTAssertNil(diff)
103+
var tempResultMovie = resultMovie
104+
105+
XCTAssertNotNil(tempResultMovie.url)
106+
tempResultMovie.url = nil
107+
XCTAssertNoDifference(tempResultMovie, movie)
108+
109+
try await verify(resultMovie)
103110
}
104111

105112
func testUpdateFailure() async throws {

Tests/CoreDataRepositoryTests/CoreDataXCTestCase.swift

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import Combine
1010
import CoreData
1111
import CoreDataRepository
12+
import CustomDump
1213
import XCTest
1314

1415
class CoreDataXCTestCase: XCTestCase {
@@ -49,4 +50,40 @@ class CoreDataXCTestCase: XCTestCase {
4950
_repository = nil
5051
cancellables.forEach { $0.cancel() }
5152
}
53+
54+
func verify<T>(_ item: T) async throws where T: UnmanagedModel {
55+
guard let url = item.managedRepoUrl else {
56+
XCTFail("Failed to verify item in store because it has no URL")
57+
return
58+
}
59+
60+
let context = try repositoryContext()
61+
let coordinator = try container().persistentStoreCoordinator
62+
context.performAndWait {
63+
guard let objectID = coordinator.managedObjectID(forURIRepresentation: url) else {
64+
XCTFail("Failed to verify item in store because no NSManagedObjectID found in viewContext from URL.")
65+
return
66+
}
67+
var _object: NSManagedObject?
68+
do {
69+
_object = try context.existingObject(with: objectID)
70+
} catch {
71+
XCTFail(
72+
"Failed to verify item in store because it was not found by its NSManagedObjectID. Error: \(error.localizedDescription)"
73+
)
74+
return
75+
}
76+
77+
guard let object = _object else {
78+
XCTFail("Failed to verify item in store because it was not found by its NSManagedObjectID")
79+
return
80+
}
81+
82+
guard let managedItem = object as? T.RepoManaged else {
83+
XCTFail("Failed to verify item in store because it failed to cast to RepoManaged type.")
84+
return
85+
}
86+
XCTAssertNoDifference(item, managedItem.asUnmanaged)
87+
}
88+
}
5289
}

0 commit comments

Comments
 (0)