Skip to content

Commit

Permalink
chore: added more test cases
Browse files Browse the repository at this point in the history
  • Loading branch information
pallabmaiti authored Mar 16, 2024
1 parent a7eff6b commit 4d436f0
Show file tree
Hide file tree
Showing 12 changed files with 343 additions and 17 deletions.
44 changes: 40 additions & 4 deletions FindingFalcon.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@
EDE92DE02B97216000C6A055 /* SelectVehicleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDE92DDF2B97216000C6A055 /* SelectVehicleView.swift */; };
EDE92DE22B9757B400C6A055 /* DestinationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDE92DE12B9757B400C6A055 /* DestinationView.swift */; };
EDE92DE42B9779AF00C6A055 /* FindFalconPlanetsAndVehiclesWorker.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDE92DE32B9779AF00C6A055 /* FindFalconPlanetsAndVehiclesWorker.swift */; };
EDFE181D2BA5A77C0085A0E8 /* DestinationViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDFE181C2BA5A77C0085A0E8 /* DestinationViewTests.swift */; };
EDFE18252BA5C3140085A0E8 /* FindFalconInteractorErrorMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDFE18242BA5C3140085A0E8 /* FindFalconInteractorErrorMock.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -144,6 +146,8 @@
EDE92DDF2B97216000C6A055 /* SelectVehicleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectVehicleView.swift; sourceTree = "<group>"; };
EDE92DE12B9757B400C6A055 /* DestinationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DestinationView.swift; sourceTree = "<group>"; };
EDE92DE32B9779AF00C6A055 /* FindFalconPlanetsAndVehiclesWorker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FindFalconPlanetsAndVehiclesWorker.swift; sourceTree = "<group>"; };
EDFE181C2BA5A77C0085A0E8 /* DestinationViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DestinationViewTests.swift; sourceTree = "<group>"; };
EDFE18242BA5C3140085A0E8 /* FindFalconInteractorErrorMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FindFalconInteractorErrorMock.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -220,14 +224,13 @@
ED5C88332BA3625F00D97AE3 /* FindFalcon */ = {
isa = PBXGroup;
children = (
ED5C88612BA4A58C00D97AE3 /* FindFalconDataModelTests.swift */,
ED5C88632BA4B79800D97AE3 /* FindFalconDataStoreTests.swift */,
ED5C88572BA4823500D97AE3 /* FindFalconInteractorTests.swift */,
ED5C885F2BA4829100D97AE3 /* FindFalconPlanetsAndVehiclesWorkerTests.swift */,
ED5C88592BA4824C00D97AE3 /* FindFalconPresenterTests.swift */,
ED5C885D2BA4828200D97AE3 /* FindFalconTokenWorkerTests.swift */,
ED5C885B2BA4826900D97AE3 /* FindFalconViewTests.swift */,
ED5C884C2BA451B400D97AE3 /* Mocks */,
EDFE18232BA5A8A80085A0E8 /* Models */,
EDFE181F2BA5A7AC0085A0E8 /* UIComponents */,
EDFE181E2BA5A78F0085A0E8 /* Workers */,
);
path = FindFalcon;
sourceTree = "<group>";
Expand Down Expand Up @@ -257,6 +260,7 @@
isa = PBXGroup;
children = (
ED5C884D2BA47D0F00D97AE3 /* FindFalconDisplayMock.swift */,
EDFE18242BA5C3140085A0E8 /* FindFalconInteractorErrorMock.swift */,
ED5C884F2BA47D2200D97AE3 /* FindFalconInteractorMock.swift */,
ED5C884A2BA4514D00D97AE3 /* FindFalconModelMocks.swift */,
ED5C88552BA47E4100D97AE3 /* FindFalconPlanetsAndVehiclesWorkerMock.swift */,
Expand Down Expand Up @@ -377,6 +381,32 @@
path = UIComponents;
sourceTree = "<group>";
};
EDFE181E2BA5A78F0085A0E8 /* Workers */ = {
isa = PBXGroup;
children = (
ED5C885F2BA4829100D97AE3 /* FindFalconPlanetsAndVehiclesWorkerTests.swift */,
ED5C885D2BA4828200D97AE3 /* FindFalconTokenWorkerTests.swift */,
);
path = Workers;
sourceTree = "<group>";
};
EDFE181F2BA5A7AC0085A0E8 /* UIComponents */ = {
isa = PBXGroup;
children = (
EDFE181C2BA5A77C0085A0E8 /* DestinationViewTests.swift */,
);
path = UIComponents;
sourceTree = "<group>";
};
EDFE18232BA5A8A80085A0E8 /* Models */ = {
isa = PBXGroup;
children = (
ED5C88612BA4A58C00D97AE3 /* FindFalconDataModelTests.swift */,
ED5C88632BA4B79800D97AE3 /* FindFalconDataStoreTests.swift */,
);
path = Models;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
Expand Down Expand Up @@ -411,6 +441,8 @@
EDE92D912B95FEAF00C6A055 /* PBXTargetDependency */,
);
name = FindingFalconTests;
packageProductDependencies = (
);
productName = FindingFalconTests;
productReference = EDE92D8F2B95FEAF00C6A055 /* FindingFalconTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
Expand Down Expand Up @@ -443,6 +475,8 @@
Base,
);
mainGroup = EDE92D762B95FEAC00C6A055;
packageReferences = (
);
productRefGroup = EDE92D802B95FEAC00C6A055 /* Products */;
projectDirPath = "";
projectRoot = "";
Expand Down Expand Up @@ -519,8 +553,10 @@
ED5C88502BA47D2200D97AE3 /* FindFalconInteractorMock.swift in Sources */,
ED5C88542BA47E3100D97AE3 /* FindFalconTokenWorkerMock.swift in Sources */,
ED5C88462BA44EF500D97AE3 /* FoundFalconViewTests.swift in Sources */,
EDFE181D2BA5A77C0085A0E8 /* DestinationViewTests.swift in Sources */,
ED5C88352BA42AA700D97AE3 /* FoundFalconPresenterMock.swift in Sources */,
ED5C88622BA4A58C00D97AE3 /* FindFalconDataModelTests.swift in Sources */,
EDFE18252BA5C3140085A0E8 /* FindFalconInteractorErrorMock.swift in Sources */,
ED5C884E2BA47D0F00D97AE3 /* FindFalconDisplayMock.swift in Sources */,
ED5C88642BA4B79800D97AE3 /* FindFalconDataStoreTests.swift in Sources */,
ED5C88312BA3520A00D97AE3 /* ResponseHandlerTests.swift in Sources */,
Expand Down
16 changes: 9 additions & 7 deletions FindingFalcon/FindFalcon/FindFalconView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ struct FindFalconView: View {
var interactor: FindFalconBusinessLogic?
var router: FindFalconRouter?

@ObservedObject private var dataStore = FindFalconDataStore()
@ObservedObject private var dataModel = FindFalconDataModel()

@ObservedObject var dataStore = FindFalconDataStore()
@ObservedObject var dataModel = FindFalconDataModel()

var onError: (() -> Void)?

var body: some View {
NavigationView {
Form {
Expand Down Expand Up @@ -57,7 +59,6 @@ struct FindFalconView: View {
Task {
await getPlanetsAndVehicles()
await retrieveToken()
dataStore.isLoading = false
}
}
.navigationTitle("Find Falcon")
Expand Down Expand Up @@ -95,6 +96,7 @@ extension FindFalconView: FindFalconDisplayLogic {

func displayToken(viewModel: FindingFalcon.RetrieveToken.ViewModel) {
dataStore.token = viewModel.token
dataStore.isLoading = false
}
}

Expand All @@ -115,13 +117,13 @@ extension FindFalconView {
}
}

private func startAgain() {
func startAgain() {
dataModel.reset()
dataModel.destinations.first?.planetList = dataStore.planetList
dataModel.destinations.first?.vehicleList = dataStore.vehicleList
}

private func showError(_ error: Error) {
print(error.localizedDescription)
func showError(_ error: Error) {
onError?()
}
}
7 changes: 7 additions & 0 deletions FindingFalcon/FindFalcon/Models/FindFalconDataStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,11 @@ final class FindFalconDataStore: ObservableObject {
@Published var vehicleList: [Vehicle] = []
@Published var token: Token?
@Published var isLoading = true

required init(planetList: [Planet] = [], vehicleList: [Vehicle] = [], token: Token? = nil, isLoading: Bool = true) {
self.planetList = planetList
self.vehicleList = vehicleList
self.token = token
self.isLoading = isLoading
}
}
12 changes: 6 additions & 6 deletions FindingFalcon/FindFalcon/UIComponents/DestinationView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ struct DestinationView: View {
.frame(maxWidth: .infinity, alignment: .trailing)
Spacer()
Button(action:{
onButtonSelect()
onSelectButton()
}) {
HStack(alignment: .center, spacing: 10) {
Image(systemName: isSelected ? "chevron.up" : "chevron.down")
Expand All @@ -41,21 +41,21 @@ struct DestinationView: View {
Text(item.name)
.frame(maxWidth: .infinity, alignment: .trailing)
.onTapGesture {
updatePlanetList(item)
onSelectPlanet(item)
}
Divider()
}
}
}
if destination.selectedPlanet != nil {
ForEach(destination.vehicleList, id: \.self) {
SelectVehicleView(vehicle: $0, selectedVehicle: destination.selectedVehicle, onSelectVehicle: updateVehicleList)
SelectVehicleView(vehicle: $0, selectedVehicle: destination.selectedVehicle, onSelectVehicle: onSelectVehicle)
}
}
}
}

private func updateVehicleList(_ vehicle: Vehicle) {
func onSelectVehicle(_ vehicle: Vehicle) {
// if vehicle is not available, return from here.
guard vehicle.totalNo > 0 else {
return
Expand All @@ -72,13 +72,13 @@ struct DestinationView: View {
onVehicleSelect?()
}

private func updatePlanetList(_ planet: Planet) {
func onSelectPlanet(_ planet: Planet) {
destination.selectedPlanet = planet
isSelected = false
onPlanetSelect?()
}

private func onButtonSelect() {
func onSelectButton() {
isSelected = !isSelected
}
}
125 changes: 125 additions & 0 deletions FindingFalconTests/FindFalcon/FindFalconViewTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import XCTest
@testable import FindingFalcon

final class FindFalconViewTests: XCTestCase {

@MainActor func test_retrieveToken() async {
var view = FindFalconView()

Expand All @@ -30,4 +31,128 @@ final class FindFalconViewTests: XCTestCase {

XCTAssertTrue(interactor.getPlanetsAndVehiclesCalled)
}

@MainActor func test_DataStore_Vehicle_And_Planet_List() async throws {
let presenter = FindFalconPresenter()
let interactor = FindFalconInteractor()

let vehicleName: String = .mockRandom()
let vehicle: FindingFalcon.LoadVehicles.Response = .mockRandom(name: vehicleName, totalNo: 1, maxDistance: 200, speed: 2)

let planetName: String = .mockRandom()
let planet: FindingFalcon.LoadPlanets.Response = .mockRandom(name: planetName, distance: 300)

let response: FindingFalcon.LoadPlanetsAndVehicles.Response = .mockRandom(planets: [planet], vehicles: [vehicle])
let planetsAndVehiclesWorker = FindFalconPlanetsAndVehiclesWorkerMock(response: response)

interactor.planetsAndVehiclesWorker = planetsAndVehiclesWorker

var view = FindFalconView()
view.interactor = interactor
interactor.presenter = presenter
presenter.view = view

XCTAssertEqual(view.dataStore.planetList, [])
XCTAssertEqual(view.dataStore.vehicleList, [])
XCTAssertEqual(view.dataModel.destinations.first?.planetList, [])
XCTAssertEqual(view.dataModel.destinations.first?.vehicleList, [])

await view.getPlanetsAndVehicles()

XCTAssertEqual(view.dataStore.planetList, [Planet(name: planetName, distance: 300)])
XCTAssertEqual(view.dataStore.vehicleList, [Vehicle(name: vehicleName, totalNo: 1, maxDistance: 200, speed: 2)])
XCTAssertEqual(view.dataModel.destinations.first?.planetList, [Planet(name: planetName, distance: 300)])
XCTAssertEqual(view.dataModel.destinations.first?.vehicleList, [Vehicle(name: vehicleName, totalNo: 1, maxDistance: 200, speed: 2)])
}

@MainActor func test_DataStore_Token() async throws {
let presenter = FindFalconPresenter()
let interactor = FindFalconInteractor()

let token: String = .mockRandom()
let response: FindingFalcon.RetrieveToken.Response = .mockRandom(token: token)
let tokenWorker = FindFalconTokenWorkerMock(response: response)

interactor.tokenWorker = tokenWorker

var view = FindFalconView()
view.interactor = interactor
interactor.presenter = presenter
presenter.view = view

XCTAssertNil(view.dataStore.token)

await view.retrieveToken()

XCTAssertEqual(view.dataStore.token, Token(token: token))
}

@MainActor func test_DataStore_isLoading() async throws {
let presenter = FindFalconPresenter()
let interactor = FindFalconInteractor()

let tokenWorker = FindFalconTokenWorkerMock()

interactor.tokenWorker = tokenWorker

var view = FindFalconView()
view.interactor = interactor
interactor.presenter = presenter
presenter.view = view

XCTAssertTrue(view.dataStore.isLoading)

await view.retrieveToken()

XCTAssertFalse(view.dataStore.isLoading)
}

@MainActor func test_DataFetch_onError() async throws {
let expectation = expectation(description: "Error should occur")
expectation.expectedFulfillmentCount = 2

let interactor = FindFalconInteractorErrorMock()

var view = FindFalconView()
view.interactor = interactor

view.onError = {
expectation.fulfill()
}

await view.getPlanetsAndVehicles()
await view.retrieveToken()

// xcodebuild on CI is not working.
// await self.fulfillment(of: [expectation], timeout: 0.5)

waitForExpectations(timeout: 0.5)
}

@MainActor func test_startAgain() async throws {
var view = FindFalconView()

let vehicle1: Vehicle = .mockRandom(name: .mockRandom(), totalNo: 1, maxDistance: 200, speed: 2)
let vehicle2: Vehicle = .mockRandom(name: .mockRandom(), totalNo: 1, maxDistance: 200, speed: 2)

let planet1: Planet = .mockRandom(name: .mockRandom(), distance: 300)
let planet2: Planet = .mockRandom(name: .mockRandom(), distance: 300)

view.dataStore = .mockRandom(planetList: [planet1, planet2], vehicleList: [vehicle1, vehicle2])

let destination1: Destination = .mockRandom(name: .mockRandom(), planetList: [planet1, planet2], vehicleList: [vehicle1, vehicle2], selectedVehicle: vehicle1, selectedPlanet: planet2)
let destination2: Destination = .mockRandom(name: .mockRandom(), planetList: [planet1, planet2], vehicleList: [vehicle1, vehicle2], selectedVehicle: vehicle2, selectedPlanet: planet1)
view.dataModel = .mockRandom(destinations: [destination1, destination2])

view.startAgain()

XCTAssertEqual(destination1.planetList, [planet1, planet2])
XCTAssertEqual(destination1.vehicleList, [vehicle1, vehicle2])
XCTAssertNil(destination1.selectedVehicle)
XCTAssertNil(destination1.selectedPlanet)
XCTAssertEqual(destination2.planetList, [])
XCTAssertEqual(destination2.vehicleList, [])
XCTAssertNil(destination2.selectedVehicle)
XCTAssertNil(destination2.selectedPlanet)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// FindFalconInteractorErrorMock.swift
// FindingFalconTests
//
// Created by Pallab Maiti on 16/03/24.
//

import Foundation
@testable import FindingFalcon

class FindFalconInteractorErrorMock: FindFalconBusinessLogic {

func retrieveToken() async throws {
throw APIError.noResponse
}

func getPlanetsAndVehicles() async throws {
throw APIError.noResponse
}
}
15 changes: 15 additions & 0 deletions FindingFalconTests/FindFalcon/Mocks/ModelMocks.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,18 @@ extension Token: AnyMockable {
return Token(token: token)
}
}

extension FindFalconDataStore: AnyMockable {
public static func mockAny() -> Self {
return mockRandom()
}

static func mockRandom(
planetList: [Planet] = [.mockAny()],
vehicleList: [Vehicle] = [.mockAny()],
token: Token? = .mockAny(),
isLoading: Bool = .mockAny()
) -> Self {
return .init(planetList: planetList, vehicleList: vehicleList, token: token, isLoading: isLoading)
}
}
Loading

0 comments on commit 4d436f0

Please sign in to comment.