feat: added UI and Unit Tests
This commit is contained in:
@@ -1,17 +0,0 @@
|
|||||||
//
|
|
||||||
// QuizAppTests.swift
|
|
||||||
// QuizAppTests
|
|
||||||
//
|
|
||||||
// Created by Paul Nowotka on 02.08.25.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Testing
|
|
||||||
@testable import QuizApp
|
|
||||||
|
|
||||||
struct QuizAppTests {
|
|
||||||
|
|
||||||
@Test func example() async throws {
|
|
||||||
// Write your test here and use APIs like `#expect(...)` to check expected conditions.
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -2,40 +2,63 @@
|
|||||||
// QuizAppUITests.swift
|
// QuizAppUITests.swift
|
||||||
// QuizAppUITests
|
// QuizAppUITests
|
||||||
//
|
//
|
||||||
// Created by Paul Nowotka on 02.08.25.
|
// Created by Paul on 02.08.25.
|
||||||
//
|
//
|
||||||
|
|
||||||
import XCTest
|
import XCTest
|
||||||
|
|
||||||
final class QuizAppUITests: XCTestCase {
|
final class QuizAppUITests: XCTestCase {
|
||||||
|
var app: XCUIApplication!
|
||||||
|
|
||||||
override func setUpWithError() throws {
|
override func setUpWithError() throws {
|
||||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
|
||||||
|
|
||||||
// In UI tests it is usually best to stop immediately when a failure occurs.
|
|
||||||
continueAfterFailure = false
|
continueAfterFailure = false
|
||||||
|
app = XCUIApplication()
|
||||||
// In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
|
app.launch()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tearDownWithError() throws {
|
override func tearDownWithError() throws {
|
||||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainActor
|
func testMultipleChoice() throws {
|
||||||
func testExample() throws {
|
app/*@START_MENU_TOKEN@*/.buttons.containing(.staticText, identifier: "Hauptstädte").firstMatch/*[[".buttons",".containing(.staticText, identifier: \"Highscore: 7\").firstMatch",".containing(.staticText, identifier: \"Hauptstädte\").firstMatch",".otherElements.buttons[\"Hauptstädte, Highscore: 7\"]",".buttons[\"Hauptstädte, Highscore: 7\"]"],[[[-1,4],[-1,3],[-1,0,1]],[[-1,2],[-1,1]]],[2,0]]@END_MENU_TOKEN@*/.tap()
|
||||||
// UI tests must launch the application that they test.
|
|
||||||
let app = XCUIApplication()
|
//Erscheint die erste Frage korrekt?
|
||||||
app.launch()
|
let q1 = app.staticTexts["Was ist die Hauptstadt von Frankreich?"]
|
||||||
|
XCTAssertTrue(q1.waitForExistence(timeout: 1))
|
||||||
|
|
||||||
|
app.buttons["Paris"].tap()
|
||||||
|
|
||||||
|
//Korrekte Auswertung?
|
||||||
|
XCTAssertTrue(app.staticTexts["✅ Richtig!"].waitForExistence(timeout: 1))
|
||||||
|
XCTAssertTrue(app.buttons["Nächste Frage"].exists)
|
||||||
|
|
||||||
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainActor
|
func testEstimationSliderDisabledAfterSubmit() throws {
|
||||||
func testLaunchPerformance() throws {
|
app.staticTexts["Schätzen"].tap()
|
||||||
// This measures how long it takes to launch your application.
|
|
||||||
measure(metrics: [XCTApplicationLaunchMetric()]) {
|
let slider = app.sliders.element(boundBy: 0)
|
||||||
XCUIApplication().launch()
|
XCTAssertTrue(slider.waitForExistence(timeout: 2))
|
||||||
}
|
slider.adjust(toNormalizedSliderPosition: 0.7)
|
||||||
|
|
||||||
|
let submit = app.buttons["Antwort abgeben"]
|
||||||
|
XCTAssertTrue(submit.exists)
|
||||||
|
submit.tap()
|
||||||
|
|
||||||
|
// Slider muss disabled sein
|
||||||
|
XCTAssertFalse(slider.isEnabled)
|
||||||
|
|
||||||
|
XCTAssertTrue(app.buttons["Nächste Frage"].waitForExistence(timeout: 2))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func testQuit() throws {
|
||||||
|
app/*@START_MENU_TOKEN@*/.buttons.containing(.staticText, identifier: "Hauptstädte").firstMatch/*[[".buttons",".containing(.staticText, identifier: \"Highscore: 7\").firstMatch",".containing(.staticText, identifier: \"Hauptstädte\").firstMatch",".otherElements.buttons[\"Hauptstädte, Highscore: 7\"]",".buttons[\"Hauptstädte, Highscore: 7\"]"],[[[-1,4],[-1,3],[-1,0,1]],[[-1,2],[-1,1]]],[2,0]]@END_MENU_TOKEN@*/.tap()
|
||||||
|
app/*@START_MENU_TOKEN@*/.buttons["Abbrechen"]/*[[".otherElements[\"Abbrechen\"].buttons.firstMatch",".otherElements.buttons[\"Abbrechen\"]",".buttons[\"Abbrechen\"]"],[[[-1,2],[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.tap()
|
||||||
|
app/*@START_MENU_TOKEN@*/.buttons["Quiz verlassen"]/*[[".otherElements.buttons[\"Quiz verlassen\"]",".buttons[\"Quiz verlassen\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.tap()
|
||||||
|
let welcome_msg = app.staticTexts["Willkommen!"]
|
||||||
|
XCTAssertTrue(welcome_msg.waitForExistence(timeout: 1))
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
//
|
|
||||||
// QuizAppUITestsLaunchTests.swift
|
|
||||||
// QuizAppUITests
|
|
||||||
//
|
|
||||||
// Created by Paul Nowotka on 02.08.25.
|
|
||||||
//
|
|
||||||
|
|
||||||
import XCTest
|
|
||||||
|
|
||||||
final class QuizAppUITestsLaunchTests: XCTestCase {
|
|
||||||
|
|
||||||
override class var runsForEachTargetApplicationUIConfiguration: Bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
override func setUpWithError() throws {
|
|
||||||
continueAfterFailure = false
|
|
||||||
}
|
|
||||||
|
|
||||||
@MainActor
|
|
||||||
func testLaunch() throws {
|
|
||||||
let app = XCUIApplication()
|
|
||||||
app.launch()
|
|
||||||
|
|
||||||
// Insert steps here to perform after app launch but before taking a screenshot,
|
|
||||||
// such as logging into a test account or navigating somewhere in the app
|
|
||||||
|
|
||||||
let attachment = XCTAttachment(screenshot: app.screenshot())
|
|
||||||
attachment.name = "Launch Screen"
|
|
||||||
attachment.lifetime = .keepAlways
|
|
||||||
add(attachment)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
107
QuizAppUnitTests/QuizAppUnitTests.swift
Normal file
107
QuizAppUnitTests/QuizAppUnitTests.swift
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
//
|
||||||
|
// QuizAppUnitTests.swift
|
||||||
|
// QuizAppUnitTests
|
||||||
|
//
|
||||||
|
// Created by Paul on 08.09.25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import XCTest
|
||||||
|
|
||||||
|
@testable import QuizApp
|
||||||
|
|
||||||
|
final class QuizAppUnitTests: XCTestCase {
|
||||||
|
|
||||||
|
private func makeMC(
|
||||||
|
question: String,
|
||||||
|
answers: [String] = ["A", "B", "C"],
|
||||||
|
correct: Int
|
||||||
|
) -> QuizQuestion {
|
||||||
|
struct Payload: Encodable {
|
||||||
|
let question: String
|
||||||
|
let answers: [String]
|
||||||
|
let correctAnswer: Int
|
||||||
|
}
|
||||||
|
let payload = Payload(
|
||||||
|
question: question,
|
||||||
|
answers: answers,
|
||||||
|
correctAnswer: correct
|
||||||
|
)
|
||||||
|
let data = try! JSONEncoder().encode(payload)
|
||||||
|
return try! JSONDecoder().decode(QuizQuestion.self, from: data)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func makeEst(
|
||||||
|
question: String,
|
||||||
|
correct: Double,
|
||||||
|
min: Double = 0,
|
||||||
|
max: Double = 100,
|
||||||
|
unit: String = ""
|
||||||
|
) -> QuizQuestion {
|
||||||
|
struct Payload: Encodable {
|
||||||
|
let type = "estimation"
|
||||||
|
let question: String
|
||||||
|
let minValue: Double
|
||||||
|
let maxValue: Double
|
||||||
|
let correctValue: Double
|
||||||
|
let unit: String
|
||||||
|
}
|
||||||
|
let payload = Payload(
|
||||||
|
question: question,
|
||||||
|
minValue: min,
|
||||||
|
maxValue: max,
|
||||||
|
correctValue: correct,
|
||||||
|
unit: unit
|
||||||
|
)
|
||||||
|
let data = try! JSONEncoder().encode(payload)
|
||||||
|
return try! JSONDecoder().decode(QuizQuestion.self, from: data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testIncrementScore_CorrectAnswer() {
|
||||||
|
let vm = QuizViewModel()
|
||||||
|
vm.questions = [makeMC(question: "Q1", correct: 2)]
|
||||||
|
vm.currentQuestionIndex = 0
|
||||||
|
XCTAssertEqual(vm.score, 0)
|
||||||
|
vm.incrementScore(selectedIndex: 2)
|
||||||
|
XCTAssertEqual(vm.score, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testIncrementScore_WrongAnswer() {
|
||||||
|
let vm = QuizViewModel()
|
||||||
|
vm.questions = [makeMC(question: "Q1", correct: 2)]
|
||||||
|
vm.currentQuestionIndex = 0
|
||||||
|
vm.incrementScore(selectedIndex: 1)
|
||||||
|
XCTAssertEqual(vm.score, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testLoadNextQuestion_NotFinished() {
|
||||||
|
let vm = QuizViewModel()
|
||||||
|
vm.questions = [
|
||||||
|
makeMC(question: "Q1", correct: 0),
|
||||||
|
makeMC(question: "Q2", correct: 0),
|
||||||
|
]
|
||||||
|
vm.currentQuestionIndex = 0
|
||||||
|
vm.loadNextQuestion()
|
||||||
|
XCTAssertFalse(vm.isQuizFinished)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testLoadNextQuestion_Finished() {
|
||||||
|
let vm = QuizViewModel()
|
||||||
|
vm.questions = [makeMC(question: "Q1", correct: 0)]
|
||||||
|
vm.currentQuestionIndex = 0
|
||||||
|
vm.loadNextQuestion()
|
||||||
|
XCTAssertTrue(vm.isQuizFinished)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testPointsForEstimation_onePoint() {
|
||||||
|
let vm = QuizViewModel()
|
||||||
|
let p = vm.pointsForEstimation(guess: 109, correct: 100, maxPoints: 1)
|
||||||
|
XCTAssertEqual(p, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testPointsForEstimation_ZeroPoints() {
|
||||||
|
let vm = QuizViewModel()
|
||||||
|
let p = vm.pointsForEstimation(guess: 111, correct: 100, maxPoints: 1)
|
||||||
|
XCTAssertEqual(p, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user