swift
132 lines · 2 tabs
Sofia Martinez
Jan 2026
2 tabs
import XCTest
import Combine
@testable import MyApp
class PostsViewModelTests: XCTestCase {
var viewModel: PostsViewModel!
var mockNetworkService: MockNetworkService!
var cancellables: Set<AnyCancellable>!
override func setUp() {
super.setUp()
mockNetworkService = MockNetworkService()
viewModel = PostsViewModel(networkService: mockNetworkService)
cancellables = []
}
override func tearDown() {
viewModel = nil
mockNetworkService = nil
cancellables = nil
super.tearDown()
}
func testLoadPostsSuccess() {
// Arrange
let expectedPosts = [
Post(id: 1, title: "Test Post", body: "Body", authorId: 1)
]
mockNetworkService.postsToReturn = expectedPosts
let expectation = XCTestExpectation(description: "Posts loaded")
viewModel.$posts
.dropFirst() // Skip initial empty state
.sink { posts in
XCTAssertEqual(posts.count, 1)
XCTAssertEqual(posts.first?.title, "Test Post")
expectation.fulfill()
}
.store(in: &cancellables)
// Act
viewModel.loadPosts()
// Assert
wait(for: [expectation], timeout: 1.0)
XCTAssertFalse(viewModel.isLoading)
XCTAssertNil(viewModel.errorMessage)
}
func testLoadPostsFailure() {
// Arrange
mockNetworkService.shouldFail = true
let expectation = XCTestExpectation(description: "Error received")
viewModel.$errorMessage
.dropFirst()
.sink { error in
if error != nil {
expectation.fulfill()
}
}
.store(in: &cancellables)
// Act
viewModel.loadPosts()
// Assert
wait(for: [expectation], timeout: 1.0)
XCTAssertNotNil(viewModel.errorMessage)
XCTAssertTrue(viewModel.posts.isEmpty)
}
func testSearchDebounce() {
// Test that search is debounced
let expectation = XCTestExpectation(description: "Search executed once")
expectation.expectedFulfillmentCount = 1
mockNetworkService.searchCallCount = 0
// Act - rapid changes
viewModel.searchQuery = "t"
viewModel.searchQuery = "te"
viewModel.searchQuery = "tes"
viewModel.searchQuery = "test"
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
// Assert - only one search call after debounce
XCTAssertEqual(self.mockNetworkService.searchCallCount, 1)
expectation.fulfill()
}
wait(for: [expectation], timeout: 1.0)
}
}
import Foundation
import Combine
class MockNetworkService: NetworkServiceProtocol {
var postsToReturn: [Post] = []
var shouldFail = false
var searchCallCount = 0
func fetchPosts() -> AnyPublisher<[Post], Error> {
if shouldFail {
return Fail(error: URLError(.badServerResponse))
.eraseToAnyPublisher()
}
return Just(postsToReturn)
.setFailureType(to: Error.self)
.eraseToAnyPublisher()
}
func searchPosts(query: String) -> AnyPublisher<[Post], Error> {
searchCallCount += 1
if shouldFail {
return Fail(error: URLError(.badServerResponse))
.eraseToAnyPublisher()
}
let filtered = postsToReturn.filter { post in
post.title.localizedCaseInsensitiveContains(query)
}
return Just(filtered)
.setFailureType(to: Error.self)
.eraseToAnyPublisher()
}
}
2 files · swift
Explain with highlit
Unit tests verify code behavior in isolation using XCTest framework. I create test classes inheriting from XCTestCase with test prefixed methods. Each test has arrange-act-assert structure: set up dependencies, execute code, verify results with XCTAssert methods. For testing ViewModels, I inject mock dependencies through initializers to control external behavior. Mocks implement protocols, returning predetermined values or tracking method calls. Async tests use expectations—create with expectation(description:), fulfill when async completes, wait with waitForExpectations. Test-driven development guides design toward testable, decoupled code. Running tests frequently catches regressions early.
Related snips
ruby
class CommentsController < ApplicationController
before_action :set_post
def create
@comment = @post.comments.build(comment_params)
System test: asserting Turbo Stream responses
rails
hotwire
turbo
by codesnips
4 tabs
swift
import Combine
import Foundation
class SearchViewModel: ObservableObject {
@Published var searchQuery = ""
@Published var results: [SearchResult] = []
Combine operators for data transformation
swift
combine
reactive
by Sofia Martinez
1 tab
swift
import SwiftUI
struct ContentView: View {
@State private var username = ""
@State private var isLoggedIn = false
@StateObject private var viewModel = LoginViewModel()
SwiftUI declarative UI with state management
swift
swiftui
ios
by Sofia Martinez
2 tabs
rust
use my_crate::add;
#[test]
fn test_public_api() {
assert_eq!(add(3, 4), 7);
}
Integration tests in tests/ directory
rust
testing
integration
by Marcus Chen
1 tab
swift
import SwiftUI
struct CardModifier: ViewModifier {
var backgroundColor: Color = .white
var cornerRadius: CGFloat = 12
var shadowRadius: CGFloat = 5
Custom SwiftUI view modifiers for reusability
swift
swiftui
ios
by Sofia Martinez
2 tabs
kotlin
package com.example.myapp.data.repository
import com.example.myapp.data.local.PostDao
import com.example.myapp.data.local.PostEntity
import com.example.myapp.data.remote.ApiService
import com.example.myapp.models.Post
Unit testing with JUnit and MockK
kotlin
android
testing
by Alex Chen
2 tabs
Share this code
Here's the card — post it anywhere.