Skip to content
All work

Case study · University course, TU Wien

Software Quality Assurance

Coursework in Software Quality Assurance at TU Wien, built around LEIHS, a Spring Boot backend for renting out hardware that the course provided. Over one semester I took it from a review of the specification to a test plan to 99 automated tests, with TDD, stubs and mocks, and static analysis.

Individual coursework
Role
Winter semester 2024/25
Timeline
Java 21, Spring Boot 3.2, JUnit 5, Mockito, H2, Checkstyle, SonarLint, GitLab CI
Stack
Completed course
Status

The project

LEIHS rents out hardware: customers, bookings and invoices, a discount and hardware-point system, and repairs through an external HTTP service. The course provided it as a template and followed this one system through the whole semester, from the specification to tested code. The application code comes from the course. The analysis, the test plan, the bug fixes, the tests and the refactoring are mine.

From analysis to automated tests

  1. 01, Exercise 1

    Analysis

    • Reviewed the specification: 4 tickets, each with a question and a proposed solution.
    • Classified 6 requirements by ISO 25010 quality factors and checked that each can be verified.
    • Measurable quality goals, e.g. at most 3 clicks per core function and critical security issues fixed within 24 hours.
  2. 02, Exercise 2

    Test planning

    • A test plan across 5 test levels: unit, integration, system, acceptance and non-functional.
    • Equivalence classes and boundary values for two new requirements.
    • 16 black-box test cases, each a normal, special or error case.
  3. 03, Exercises 3–4

    Test automation

    • 99 automated tests, all passing.
    • TDD for two new device types.
    • A hand-written stub and Mockito mocks for the external repair service.
    • Checkstyle and SonarLint, and refactoring of test smells.

One edge case, start to finish

In the review of the specification I flagged an open question: when a student earns a hardware point on a booking, does it already count toward the discount on that same invoice? At 9 of 10 points, the answer decides whether the discount applies right away, so I proposed crediting the point after the booking and pricing on the balance before it. Once there was code, hardware points and discounts were the area with the most bug fixes, and I covered them with their own tests for the invoice preview.

From equivalence classes to a test

In the test plan, the new device types were split into equivalence classes. In the next exercise, the same classes became the tests, written before the feature itself.

Equivalence classes from the test plan
CategoryG1 Electronics: no bonusG2 Garden and workshop tools: bonus
Rental (G2 only)V1 1 month: +1 pointV2 longer: +2 points
InsuranceS1 noneS2 insured: −5 % on the monthly price
@ParameterizedTest
@EnumSource(value = DeviceType.class, names = {"GARDEN_TOOL", "MACHINE"})
void testCalculateHardwarePoints_ForNewToolWithOneMonthRental_ShouldEarnOneHardwarePoint(DeviceType deviceType) {
    customer.setHardwarePoints(0L);
    customer.setIsStudent(false);

    hardwareDescription.setType(deviceType);
    hardwareDescription.setMonthlyBasePrice(2000.0);

    booking.setRentDurationMonths(1);

    simpleInvoiceService.generateInvoicePreview(
            customer, List.of(booking), List.of(), LocalDateTime.now());

    long expectedHardwarePoints = 3 + 1;
    assertEquals(expectedHardwarePoints, customer.getHardwarePoints());
}
Class G2 with V1, test case 24-1 in the test plan. Slightly shortened. Written test-first: the test existed before GARDEN_TOOL and MACHINE did, and one parameterised test covers both device types in class G2.

What I did

  • Bug fixes in the template

    Fixed the hardware points, the booking price, the discount at 20 points and the minimum rental durations.

  • TDD for new device types

    Garden tools and machines earn bonus points and get 5 % off with insurance. The tests came first, then the implementation: 13 tests, all green.

  • Stub and mock for the repair service

    A hand-written stub mirrors the rules of the external service: water damage and devices 6 years or older are cancelled. Mockito mocks test the status lifecycle without a network.

  • Static analysis & refactoring

    Checkstyle and SonarLint findings fixed or justified as false positives. Test smells refactored: try/catch to assertThrows, duplicates to parameterised tests. Status strings became an enum.

Architecture

Test setup of the LEIHS backend JUnit 5 tests run against the Spring Boot context with the cost calculation, invoice, booking and repair services, which store their data in an in-memory H2 database. The repair service talks to an external repair service through an interface. In the tests it is replaced by a hand-written stub or a Mockito mock. Tests against the real external service run separately, in their own CI job. GitLab CI builds the project and runs the tests. callsJPArunsJUnit 5 testsGitLab CISpring Boot contextH2StubMockito mockReal repair serviceparameterised, TDDbuild and test stagescost calculation · invoicesbookings · repairsrepair client: an interfacein-memory test datahand-written rulesstatus lifecycletagged, own CI job
The tests run against the Spring Boot context with an in-memory H2 database. The repair service talks to the external service through an interface, which the tests replace with a stub or a Mockito mock. Tests against the real service carry their own tag and run in a separate CI job.

Results

99 tests, all passing
Unit and integration tests, run without the external service.
Core services covered
94 % line coverage on the cost calculation, 100 % on the invoice service.
Checked in CI
GitLab CI builds the project and runs the tests, with Checkstyle in the build.