Todo repository protocol (#8)
This PR contains the work done to decouple the direct use of the `ModelContext` from `SwiftData` from the view model that uses it. In addition, the project transitioned to use Swift 6 and strict concurrency which brought some issues with the unit tests, so they were amended as well. Reviewed-on: rock-n-code/todos-app#8 Co-authored-by: Javier Cicchelli <javier@rock-n-code.com> Co-committed-by: Javier Cicchelli <javier@rock-n-code.com>
This commit was merged in pull request #8.
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
import Foundation
|
||||
import SwiftData
|
||||
import Testing
|
||||
|
||||
@testable import Todos
|
||||
|
||||
@MainActor
|
||||
@Suite("NewTaskView view model tests")
|
||||
struct NewTaskViewModelTests {
|
||||
|
||||
@@ -121,11 +121,9 @@ struct NewTaskViewModelTests {
|
||||
// MARK: Functions tests
|
||||
|
||||
@Test("save creates todo with all properties")
|
||||
@MainActor
|
||||
func saveWithAllProperties() throws {
|
||||
// GIVEN
|
||||
let container = try modelContainer
|
||||
let context = container.mainContext
|
||||
let repository = MockTodoRepository()
|
||||
let viewModel = NewTaskView.ViewModel()
|
||||
|
||||
// WHEN
|
||||
@@ -133,12 +131,10 @@ struct NewTaskViewModelTests {
|
||||
viewModel.note = "Finish by end of week"
|
||||
viewModel.due = Date(timeIntervalSince1970: 1000000000)
|
||||
|
||||
viewModel.save(to: context)
|
||||
viewModel.save(to: repository)
|
||||
|
||||
// THEN
|
||||
let descriptor = FetchDescriptor<Todo>()
|
||||
let todos = try context.fetch(descriptor)
|
||||
let todo = try #require(todos.first)
|
||||
let todo = try #require(repository.todos.first)
|
||||
|
||||
#expect(todo.title == viewModel.title)
|
||||
#expect(todo.note == viewModel.note)
|
||||
@@ -147,11 +143,9 @@ struct NewTaskViewModelTests {
|
||||
}
|
||||
|
||||
@Test("save creates todo without note when note is empty")
|
||||
@MainActor
|
||||
func saveWithEmptyNote() throws {
|
||||
// GIVEN
|
||||
let container = try modelContainer
|
||||
let context = container.mainContext
|
||||
let repository = MockTodoRepository()
|
||||
let viewModel = NewTaskView.ViewModel()
|
||||
|
||||
// WHEN
|
||||
@@ -159,12 +153,10 @@ struct NewTaskViewModelTests {
|
||||
viewModel.note = ""
|
||||
viewModel.due = Date()
|
||||
|
||||
viewModel.save(to: context)
|
||||
viewModel.save(to: repository)
|
||||
|
||||
// THEN
|
||||
let descriptor = FetchDescriptor<Todo>()
|
||||
let todos = try context.fetch(descriptor)
|
||||
let todo = try #require(todos.first)
|
||||
let todo = try #require(repository.todos.first)
|
||||
|
||||
#expect(todo.title == viewModel.title)
|
||||
#expect(todo.note == nil)
|
||||
@@ -173,11 +165,9 @@ struct NewTaskViewModelTests {
|
||||
}
|
||||
|
||||
@Test("save creates todo with note containing only whitespace as nil")
|
||||
@MainActor
|
||||
func saveWithWhitespaceNote() throws {
|
||||
// GIVEN
|
||||
let container = try modelContainer
|
||||
let context = container.mainContext
|
||||
let repository = MockTodoRepository()
|
||||
let viewModel = NewTaskView.ViewModel()
|
||||
|
||||
// WHEN
|
||||
@@ -185,12 +175,10 @@ struct NewTaskViewModelTests {
|
||||
viewModel.note = " "
|
||||
viewModel.due = Date()
|
||||
|
||||
viewModel.save(to: context)
|
||||
viewModel.save(to: repository)
|
||||
|
||||
// THEN
|
||||
let descriptor = FetchDescriptor<Todo>()
|
||||
let todos = try context.fetch(descriptor)
|
||||
let todo = try #require(todos.first)
|
||||
let todo = try #require(repository.todos.first)
|
||||
|
||||
#expect(todo.title == viewModel.title)
|
||||
#expect(todo.note == nil)
|
||||
@@ -199,46 +187,24 @@ struct NewTaskViewModelTests {
|
||||
}
|
||||
|
||||
@Test("save inserts multiple todos independently")
|
||||
@MainActor
|
||||
func saveMultipleTodos() throws {
|
||||
func saveMultipleTodos() {
|
||||
// GIVEN
|
||||
let container = try modelContainer
|
||||
let context = container.mainContext
|
||||
let repository = MockTodoRepository()
|
||||
let viewModelFirst = NewTaskView.ViewModel()
|
||||
let viewModelSecond = NewTaskView.ViewModel()
|
||||
|
||||
// WHEN
|
||||
viewModelFirst.title = "First task"
|
||||
viewModelFirst.save(to: context)
|
||||
viewModelFirst.save(to: repository)
|
||||
|
||||
viewModelSecond.title = "Second task"
|
||||
viewModelSecond.note = "With a note"
|
||||
viewModelSecond.save(to: context)
|
||||
viewModelSecond.save(to: repository)
|
||||
|
||||
// THEN
|
||||
let descriptor = FetchDescriptor<Todo>()
|
||||
let todos = try context.fetch(descriptor)
|
||||
|
||||
#expect(todos.count == 2)
|
||||
#expect(todos.contains { $0.title == "First task" })
|
||||
#expect(todos.contains { $0.title == "Second task" })
|
||||
#expect(repository.todos.count == 2)
|
||||
#expect(repository.todos.contains { $0.title == "First task" })
|
||||
#expect(repository.todos.contains { $0.title == "Second task" })
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Helpers
|
||||
|
||||
private extension NewTaskViewModelTests {
|
||||
|
||||
// MARK: Computed
|
||||
|
||||
var modelContainer: ModelContainer {
|
||||
get throws {
|
||||
try ModelContainer(
|
||||
for: Todo.self,
|
||||
configurations: .init(isStoredInMemoryOnly: true)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user