<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Vincent Davis</title>
    <description>The latest articles on DEV Community by Vincent Davis (@vincent_davis_7b6665836a9).</description>
    <link>https://dev.to/vincent_davis_7b6665836a9</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3924344%2Fbc1b27ec-93e3-49a8-9ec1-85628a372281.jpg</url>
      <title>DEV Community: Vincent Davis</title>
      <link>https://dev.to/vincent_davis_7b6665836a9</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vincent_davis_7b6665836a9"/>
    <language>en</language>
    <item>
      <title>Beyond Unit Tests: Implementing BDD and Penetration Testing in GBIM</title>
      <dc:creator>Vincent Davis</dc:creator>
      <pubDate>Mon, 11 May 2026 09:43:49 +0000</pubDate>
      <link>https://dev.to/vincent_davis_7b6665836a9/beyond-unit-tests-implementing-bdd-and-penetration-testing-in-gbim-3nlc</link>
      <guid>https://dev.to/vincent_davis_7b6665836a9/beyond-unit-tests-implementing-bdd-and-penetration-testing-in-gbim-3nlc</guid>
      <description>&lt;h1&gt;
  
  
  IR Part A #4 - More Testing: Stress Testing, Penetration Testing, Security Testing, and BDD
&lt;/h1&gt;

&lt;p&gt;Prepared on: May 11, 2026&lt;br&gt;&lt;br&gt;
Project scope: &lt;code&gt;BE-GBM&lt;/code&gt; and &lt;code&gt;fe-gbm&lt;/code&gt;&lt;br&gt;&lt;br&gt;
Feature scope: account registration, account activation, login lockout, admin approval/rejection of submissions, and non-admin access control.&lt;/p&gt;
&lt;h2&gt;
  
  
  Claim Summary
&lt;/h2&gt;

&lt;p&gt;This claim demonstrates that the GBM project has implemented advanced testing in four areas required by the IR B5 rubric: security testing, penetration testing, behavior-driven development, and stress testing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security Testing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Tools and approach: GitLab SAST, Dependency Scanning, Secret Detection, and OWASP ZAP baseline.&lt;/p&gt;

&lt;p&gt;Primary evidence: the FE security pipeline passed, the BE security analyzer jobs passed in MR pipeline 279225, and the ZAP baseline job is available for staging or scheduled execution.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Penetration Testing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Tools and approach: OWASP-mapped abuse-case tests.&lt;/p&gt;

&lt;p&gt;Primary evidence: 8 concrete abuse paths cover login, registration, activation tokens, authorization, mass assignment, and email enumeration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BDD&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Tools and approach: Behave Django and Playwright BDD.&lt;/p&gt;

&lt;p&gt;Primary evidence: BE has 3 features, 12 scenarios, and 57 steps passed. FE has 3 Playwright BDD tests discovered, and &lt;code&gt;e2e-bdd&lt;/code&gt; passed in CI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stress Testing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Tools and approach: Locust.&lt;/p&gt;

&lt;p&gt;Primary evidence: registration burst, authenticated activity, quality-assurance, and admin dashboard workloads are modeled as manual headless runs with HTML/CSV output.&lt;/p&gt;

&lt;p&gt;The strongest evidence is executable and measurable: backend BDD passes, backend regression subset passes, frontend BDD/security pipeline passes, and backend security analyzer jobs pass. Stress testing is intentionally treated as manual evidence rather than a merge-request gate because staging capacity, credentials, seed data, rate limits, and email side effects can make performance numbers non-deterministic.&lt;/p&gt;
&lt;h2&gt;
  
  
  Screenshot Evidence
&lt;/h2&gt;

&lt;p&gt;Only non-trivial evidence needs screenshots. Commit links, command snippets, and static documentation paths are already explicit in text and do not need images.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Backend MR Pipeline
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvvwq8krfmuom6qffvcz5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvvwq8krfmuom6qffvcz5.png" alt=" " width="800" height="531"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Frontend MR Pipeline
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F545wyp5ojaa84twp2uwf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F545wyp5ojaa84twp2uwf.png" alt=" " width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Behave Results
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2026/kelas-d/group1-gb/be-gbm/-/jobs/802493" rel="noopener noreferrer"&gt;https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2026/kelas-d/group1-gb/be-gbm/-/jobs/802493&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foggwysoipgfif30hi6zp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foggwysoipgfif30hi6zp.png" alt=" " width="800" height="578"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  4. integrated testing with CI/CD
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhokfau7q2q7li5olgzus.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhokfau7q2q7li5olgzus.png" alt=" " width="800" height="467"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Merge Requests and Commit Links
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Merge Requests
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Repo&lt;/th&gt;
&lt;th&gt;Merge Request&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Backend&lt;/td&gt;
&lt;td&gt;&lt;a href="https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2026/kelas-d/group1-gb/be-gbm/-/merge_requests/157" rel="noopener noreferrer"&gt;https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2026/kelas-d/group1-gb/be-gbm/-/merge_requests/157&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frontend&lt;/td&gt;
&lt;td&gt;&lt;a href="https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2026/kelas-d/group1-gb/fe-gbm/-/merge_requests/141" rel="noopener noreferrer"&gt;https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2026/kelas-d/group1-gb/fe-gbm/-/merge_requests/141&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  Backend Commits Used as Evidence
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Commit&lt;/th&gt;
&lt;th&gt;Evidence Contribution&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2026/kelas-d/group1-gb/be-gbm/-/commit/64046e3c70e2ad419d14fc5580863821641991a0" rel="noopener noreferrer"&gt;https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2026/kelas-d/group1-gb/be-gbm/-/commit/64046e3c70e2ad419d14fc5580863821641991a0&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Adds the backend IR B5 testing baseline: security templates, BDD features, load-test documentation, and evidence structure.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2026/kelas-d/group1-gb/be-gbm/-/commit/8b75a9ed85b67ffc1e920a1bb842ca4503c4d684" rel="noopener noreferrer"&gt;https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2026/kelas-d/group1-gb/be-gbm/-/commit/8b75a9ed85b67ffc1e920a1bb842ca4503c4d684&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Adds executable backend BDD and penetration-testing scenarios against real DRF endpoints.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2026/kelas-d/group1-gb/be-gbm/-/commit/f9f62adb791fd5af38cc70d93bdbb0eb6ac7c62f" rel="noopener noreferrer"&gt;https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2026/kelas-d/group1-gb/be-gbm/-/commit/f9f62adb791fd5af38cc70d93bdbb0eb6ac7c62f&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Adds &lt;code&gt;behave&lt;/code&gt; and &lt;code&gt;behave-django&lt;/code&gt; to &lt;code&gt;requirements.txt&lt;/code&gt; so BDD can run consistently in the Django environment.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2026/kelas-d/group1-gb/be-gbm/-/commit/eb07e5e2a224a563605238c20fa33526a3c85e34" rel="noopener noreferrer"&gt;https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2026/kelas-d/group1-gb/be-gbm/-/commit/eb07e5e2a224a563605238c20fa33526a3c85e34&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Enables backend security analyzer execution in the MR pipeline.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2026/kelas-d/group1-gb/be-gbm/-/commit/dd64fdf164e2bbfbf36860d9caf819fbccf37341" rel="noopener noreferrer"&gt;https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2026/kelas-d/group1-gb/be-gbm/-/commit/dd64fdf164e2bbfbf36860d9caf819fbccf37341&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Finalizes backend CI and stress-testing policy: deterministic MR checks remain in CI, while stress evidence is documented through Locust manual runs.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  Frontend Commits Used as Evidence
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Commit&lt;/th&gt;
&lt;th&gt;Evidence Contribution&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2026/kelas-d/group1-gb/fe-gbm/-/commit/fff3cb1fcb7556b31399781888d90e6de15bbab8" rel="noopener noreferrer"&gt;https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2026/kelas-d/group1-gb/fe-gbm/-/commit/fff3cb1fcb7556b31399781888d90e6de15bbab8&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Adds frontend IR B5 security templates and Playwright BDD structure.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2026/kelas-d/group1-gb/fe-gbm/-/commit/dd62510177af54d760b7759299ee43df00282222" rel="noopener noreferrer"&gt;https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2026/kelas-d/group1-gb/fe-gbm/-/commit/dd62510177af54d760b7759299ee43df00282222&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Implements API-backed frontend BDD flows for registration and admin submission behavior.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2026/kelas-d/group1-gb/fe-gbm/-/commit/1e5beadbca00a422b05922935af6248ce25ea874" rel="noopener noreferrer"&gt;https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2026/kelas-d/group1-gb/fe-gbm/-/commit/1e5beadbca00a422b05922935af6248ce25ea874&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Enables frontend MR pipeline execution for security analyzers, BDD generation/discovery, and quality checks.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  Execution Evidence
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Backend Evidence
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Command or Source&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Dependency installation&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.\.venv\Scripts\python.exe -m pip install -r requirements.txt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;behave==1.2.6&lt;/code&gt; and &lt;code&gt;behave-django==1.4.0&lt;/code&gt; available in &lt;code&gt;BE-GBM\.venv&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Django system check&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.\.venv\Scripts\python.exe manage.py check&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;System check identified no issues&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Behave BDD&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.\.venv\Scripts\python.exe manage.py behave --simple --junit --junit-directory=bdd-reports&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;3 features passed, 12 scenarios passed, 57 steps passed, 0 failed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Regression subset&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.\.venv\Scripts\python.exe manage.py test authentication.tests.test_register_view authentication.tests.test_activation_views pengajuan.tests.test_views_admin&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;65 tests passed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Locust package&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.\.venv\Scripts\locust.exe --version&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;locust 2.43.4&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitLab CI lint&lt;/td&gt;
&lt;td&gt;GitLab &lt;code&gt;/ci/lint&lt;/code&gt; API with merged YAML&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;valid=True&lt;/code&gt;, &lt;code&gt;warnings=[]&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Staging register baseline&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;curl.exe -m 75 -w&lt;/code&gt; to &lt;code&gt;POST /api/auth/register/&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;HTTP 202 in 5.134493s.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  Backend MR Pipeline 279225 Evidence
&lt;/h3&gt;

&lt;p&gt;Pipeline: &lt;a href="https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2026/kelas-d/group1-gb/be-gbm/-/pipelines/279225" rel="noopener noreferrer"&gt;https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2026/kelas-d/group1-gb/be-gbm/-/pipelines/279225&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Job&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;th&gt;Why It Matters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;test&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;success&lt;/td&gt;
&lt;td&gt;Confirms the standard backend regression test suite still passes.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bdd&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;success&lt;/td&gt;
&lt;td&gt;Confirms the executable BDD scenarios are runnable in CI.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;diff_coverage&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;success&lt;/td&gt;
&lt;td&gt;Confirms changed-code coverage requirements are enforced.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;semgrep-sast&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;success&lt;/td&gt;
&lt;td&gt;Confirms backend SAST analyzer runs in the MR pipeline.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gemnasium-python-dependency_scanning&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;success&lt;/td&gt;
&lt;td&gt;Confirms Python dependency scanning runs in the MR pipeline.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;secret_detection&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;success&lt;/td&gt;
&lt;td&gt;Confirms committed secrets are scanned in the MR pipeline.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;debug-mr-analyzer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;success&lt;/td&gt;
&lt;td&gt;Confirms the existing project diagnostic job still completes.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sonarqube&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;failed&lt;/td&gt;
&lt;td&gt;Not used as evidence for this claim; the security, BDD, test, and coverage evidence above are the concrete data used here.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  Frontend Evidence
&lt;/h3&gt;

&lt;p&gt;Frontend pipeline: &lt;a href="https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2026/kelas-d/group1-gb/fe-gbm/-/pipelines/279116" rel="noopener noreferrer"&gt;https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2026/kelas-d/group1-gb/fe-gbm/-/pipelines/279116&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Evidence&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GitLab CI lint&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;valid=True&lt;/code&gt;, &lt;code&gt;warnings=[]&lt;/code&gt; for merged YAML.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BDD generation&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;npm run e2e:bdd:gen&lt;/code&gt; succeeded.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Playwright test discovery&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;npx playwright test --list&lt;/code&gt; found 3 tests across 2 generated spec files.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Targeted ESLint&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;npx eslint e2e/steps/common.steps.ts playwright.config.ts&lt;/code&gt; succeeded.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CI jobs&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;test&lt;/code&gt;, &lt;code&gt;e2e-bdd&lt;/code&gt;, &lt;code&gt;diff_coverage&lt;/code&gt;, &lt;code&gt;semgrep-sast&lt;/code&gt;, &lt;code&gt;gemnasium-dependency_scanning&lt;/code&gt;, &lt;code&gt;secret_detection&lt;/code&gt;, and &lt;code&gt;sonarqube&lt;/code&gt; succeeded.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  Demonstration of Advanced Testing Tools
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Security Testing
&lt;/h3&gt;

&lt;p&gt;Security testing is implemented through GitLab security templates and an OWASP ZAP baseline job.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Where It Runs&lt;/th&gt;
&lt;th&gt;Evidence&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GitLab SAST&lt;/td&gt;
&lt;td&gt;FE and BE MR pipelines&lt;/td&gt;
&lt;td&gt;FE &lt;code&gt;semgrep-sast&lt;/code&gt; success in pipeline 279116; BE &lt;code&gt;semgrep-sast&lt;/code&gt; success in pipeline 279225.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dependency Scanning&lt;/td&gt;
&lt;td&gt;FE and BE MR pipelines&lt;/td&gt;
&lt;td&gt;FE &lt;code&gt;gemnasium-dependency_scanning&lt;/code&gt; success; BE &lt;code&gt;gemnasium-python-dependency_scanning&lt;/code&gt; success.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secret Detection&lt;/td&gt;
&lt;td&gt;FE and BE MR pipelines&lt;/td&gt;
&lt;td&gt;FE and BE &lt;code&gt;secret_detection&lt;/code&gt; success.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OWASP ZAP Baseline&lt;/td&gt;
&lt;td&gt;BE scheduled/staging-capable job&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;dast-zap-baseline&lt;/code&gt; stores &lt;code&gt;zap-report.html&lt;/code&gt; and &lt;code&gt;zap-report.json&lt;/code&gt; artifacts when executed.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Project benefit: security checks are no longer an informal review activity only. They are reproducible CI jobs and are complemented by executable abuse-case tests for the authentication and authorization paths that matter most to GBM.&lt;/p&gt;
&lt;h3&gt;
  
  
  Penetration Testing
&lt;/h3&gt;

&lt;p&gt;The penetration-testing evidence is implemented as abuse-case integration tests. This is intentionally more concrete than a manual checklist because every abuse path has an endpoint, an expected response, and a regression signal.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Risk&lt;/th&gt;
&lt;th&gt;Endpoint or Flow&lt;/th&gt;
&lt;th&gt;Expected Result&lt;/th&gt;
&lt;th&gt;Evidence&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Broken Access Control&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;PATCH /api/pengajuan/admin/&amp;lt;uuid&amp;gt;/status/&lt;/code&gt; as non-admin&lt;/td&gt;
&lt;td&gt;403 Forbidden&lt;/td&gt;
&lt;td&gt;BDD scenario returns 403.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Identification and Authentication Failure&lt;/td&gt;
&lt;td&gt;Repeated wrong-password login&lt;/td&gt;
&lt;td&gt;429 lockout&lt;/td&gt;
&lt;td&gt;BDD login lockout scenario returns 429.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Insecure Design / Brute Force&lt;/td&gt;
&lt;td&gt;Repeated registration attempts&lt;/td&gt;
&lt;td&gt;429 rate limit&lt;/td&gt;
&lt;td&gt;BDD registration burst scenario returns 429.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Mass Assignment&lt;/td&gt;
&lt;td&gt;Register with &lt;code&gt;role=ADMIN&lt;/code&gt; and superuser-like fields&lt;/td&gt;
&lt;td&gt;400 rejection and no forged admin&lt;/td&gt;
&lt;td&gt;BDD scenario asserts no forged admin account exists.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Token Tampering&lt;/td&gt;
&lt;td&gt;Activation with modified token&lt;/td&gt;
&lt;td&gt;400 &lt;code&gt;TOKEN_INVALID&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;BDD activation scenario returns &lt;code&gt;TOKEN_INVALID&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Token Expiry&lt;/td&gt;
&lt;td&gt;Activation with expired token&lt;/td&gt;
&lt;td&gt;400 &lt;code&gt;TOKEN_EXPIRED&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;BDD activation scenario returns &lt;code&gt;TOKEN_EXPIRED&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Email Enumeration&lt;/td&gt;
&lt;td&gt;Duplicate registration&lt;/td&gt;
&lt;td&gt;Generic 202 response&lt;/td&gt;
&lt;td&gt;BDD scenario verifies no duplicate/existing wording leaks account existence.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;Invalid Admin State Transition&lt;/td&gt;
&lt;td&gt;Admin rejects/approves invalid status transition&lt;/td&gt;
&lt;td&gt;400 validation failure&lt;/td&gt;
&lt;td&gt;BDD admin scenario verifies invalid transition rejection.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Project benefit: these tests cover attacker behavior, not only happy-path behavior. They protect the project from regressions where a normal feature change accidentally weakens authorization, throttling, token validation, or privacy-preserving registration responses.&lt;/p&gt;
&lt;h3&gt;
  
  
  BDD
&lt;/h3&gt;

&lt;p&gt;BDD is used as executable specification for critical business behavior.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Scope&lt;/th&gt;
&lt;th&gt;Evidence&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Backend&lt;/td&gt;
&lt;td&gt;Behave Django&lt;/td&gt;
&lt;td&gt;Registration, duplicate email behavior, activation token validity, login lockout, admin authorization, approve/reject transitions&lt;/td&gt;
&lt;td&gt;3 features, 12 scenarios, 57 steps passed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frontend&lt;/td&gt;
&lt;td&gt;Playwright BDD&lt;/td&gt;
&lt;td&gt;User-visible registration and admin submission flows backed by API setup&lt;/td&gt;
&lt;td&gt;3 generated Playwright BDD tests discovered; &lt;code&gt;e2e-bdd&lt;/code&gt; passed in CI.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Project benefit: reviewers can read behavior in Gherkin while the CI/local commands verify the same behavior against real code paths. This reduces the gap between documentation, acceptance criteria, and regression tests.&lt;/p&gt;
&lt;h3&gt;
  
  
  Stress Testing
&lt;/h3&gt;

&lt;p&gt;Stress testing is implemented with Locust because it models user behavior as Python &lt;code&gt;HttpUser&lt;/code&gt; classes and can be run headlessly with CSV/HTML artifacts.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Locust User&lt;/th&gt;
&lt;th&gt;Behavior Modeled&lt;/th&gt;
&lt;th&gt;Authentication Need&lt;/th&gt;
&lt;th&gt;Expected Output&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RegistrationBurstUser&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;High-volume semester-start registration&lt;/td&gt;
&lt;td&gt;No login required because registration is public&lt;/td&gt;
&lt;td&gt;Request rate, failure rate, latency percentiles, HTML/CSV report.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;AdminDashboardUser&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Admin login, pending submission listing, optional status update&lt;/td&gt;
&lt;td&gt;Requires &lt;code&gt;LOCUST_ADMIN_EMAIL&lt;/code&gt; and &lt;code&gt;LOCUST_ADMIN_PASSWORD&lt;/code&gt;; optional &lt;code&gt;LOCUST_ADMIN_PENGAJUAN_ID&lt;/code&gt; is a pending submission UUID, not an admin user id&lt;/td&gt;
&lt;td&gt;Authenticated admin endpoint latency and failure report.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;KegiatanStressTestUser&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Authenticated kegiatan/statistik/periode access&lt;/td&gt;
&lt;td&gt;Requires one or more user credentials through &lt;code&gt;LOCUST_EMAIL&lt;/code&gt;/&lt;code&gt;LOCUST_PASSWORD&lt;/code&gt; or numbered credential variables&lt;/td&gt;
&lt;td&gt;Authenticated API stress profile.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GBMQualityAssuranceUser&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mixed endpoint profile across major backend API paths&lt;/td&gt;
&lt;td&gt;Requires authenticated user credentials&lt;/td&gt;
&lt;td&gt;Cross-endpoint baseline load profile.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Example commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;locust&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;locustfile.py&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;RegistrationBurstUser&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;https://gbim-staging.ppl.cs.ui.ac.id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--headless&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-u&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;50&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--run-time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;2m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--csv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;locust_register&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--html&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;locust_register.html&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;locust&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;locustfile.py&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;AdminDashboardUser&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;https://gbim-staging.ppl.cs.ui.ac.id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--headless&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-u&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;20&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--run-time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;2m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--csv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;locust_admin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--html&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;locust_admin.html&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;locust&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;locustfile.py&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;KegiatanStressTestUser&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;https://gbim-staging.ppl.cs.ui.ac.id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--headless&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-u&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;20&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--run-time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;2m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--csv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;locust_kegiatan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--html&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;locust_kegiatan.html&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claim boundary: this blog does not claim that staging meets p95 below 500ms. The measurable claim is that stress-test workloads are defined using realistic user behavior, can be executed manually, produce machine-readable CSV plus reviewable HTML reports, and correctly separate expected protection responses from unexpected failures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Measurable Project Benefits
&lt;/h2&gt;

&lt;p&gt;This section compares the project before IR B5 More Testing with the final implemented state.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Before IR B5 More Testing&lt;/th&gt;
&lt;th&gt;After Final Implementation&lt;/th&gt;
&lt;th&gt;Concrete Data&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Critical registration, activation, and admin behavior was not documented as one executable specification for this claim.&lt;/td&gt;
&lt;td&gt;Backend and frontend BDD now describe the critical journeys in Gherkin and execute them against real application behavior.&lt;/td&gt;
&lt;td&gt;BE: 3 features, 12 scenarios, 57 steps passed. FE: 3 Playwright BDD tests discovered and &lt;code&gt;e2e-bdd&lt;/code&gt; passed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security testing evidence was not consolidated into repeatable MR-level analyzer jobs plus explicit abuse-case scenarios.&lt;/td&gt;
&lt;td&gt;GitLab security analyzers run in CI, while abuse cases verify access control, throttling, token validity, and mass-assignment protection.&lt;/td&gt;
&lt;td&gt;FE pipeline 279116 security jobs passed. BE pipeline 279225 &lt;code&gt;semgrep-sast&lt;/code&gt;, &lt;code&gt;gemnasium-python-dependency_scanning&lt;/code&gt;, and &lt;code&gt;secret_detection&lt;/code&gt; passed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Penetration-testing evidence was not mapped from risks to endpoints, expected statuses, and regression checks.&lt;/td&gt;
&lt;td&gt;8 OWASP-mapped abuse paths now specify the endpoint/flow, expected result, and executable evidence.&lt;/td&gt;
&lt;td&gt;403 for non-admin access, 429 for lockout/rate-limit, 400 for invalid/tampered token paths, generic 202 for duplicate registration.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Duplicate registration behavior was not presented as privacy/security evidence for this claim.&lt;/td&gt;
&lt;td&gt;Duplicate email registration now has an explicit BDD assertion that the response remains generic and does not leak account existence.&lt;/td&gt;
&lt;td&gt;Scenario &lt;code&gt;Duplicate email registration does not leak account existence&lt;/code&gt; returns 202 and checks response wording.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Activation-token abuse behavior was not presented as a complete negative-path evidence set.&lt;/td&gt;
&lt;td&gt;Invalid and expired activation token paths are explicitly tested.&lt;/td&gt;
&lt;td&gt;BDD verifies &lt;code&gt;TOKEN_INVALID&lt;/code&gt; and &lt;code&gt;TOKEN_EXPIRED&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frontend testing evidence did not show API-backed BDD plus security scanning in one MR pipeline.&lt;/td&gt;
&lt;td&gt;The FE MR pipeline runs unit/quality jobs, BDD generation/discovery, and security analyzers.&lt;/td&gt;
&lt;td&gt;Pipeline 279116: &lt;code&gt;test&lt;/code&gt;, &lt;code&gt;e2e-bdd&lt;/code&gt;, &lt;code&gt;diff_coverage&lt;/code&gt;, &lt;code&gt;sonarqube&lt;/code&gt;, SAST, dependency scanning, and secret detection succeeded.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stress testing was not expressed as named user workloads tied to GBM roles and endpoints.&lt;/td&gt;
&lt;td&gt;Locust now models registration burst, admin dashboard, authenticated kegiatan, and mixed QA workloads.&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;locustfile.py&lt;/code&gt; defines &lt;code&gt;RegistrationBurstUser&lt;/code&gt;, &lt;code&gt;AdminDashboardUser&lt;/code&gt;, &lt;code&gt;KegiatanStressTestUser&lt;/code&gt;, and &lt;code&gt;GBMQualityAssuranceUser&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rate limiting could be misread as a failure in high-load or abuse scenarios.&lt;/td&gt;
&lt;td&gt;Expected protection is distinguished from unexpected failure.&lt;/td&gt;
&lt;td&gt;BDD expects 429 in abuse/rate-limit cases; Locust treats 202 and 429 as acceptable for registration burst.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Literature and Best Practices
&lt;/h2&gt;

&lt;p&gt;The implementation follows current industry guidance by turning general testing advice into concrete project controls.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Reference&lt;/th&gt;
&lt;th&gt;Best-Practice Principle&lt;/th&gt;
&lt;th&gt;Project Application&lt;/th&gt;
&lt;th&gt;Correlating Evidence&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OWASP Top 10 2021&lt;/td&gt;
&lt;td&gt;Web applications should explicitly test risks such as broken access control, insecure design, identification/authentication failures, and software/data integrity failures.&lt;/td&gt;
&lt;td&gt;Abuse cases target non-admin access, login lockout, registration throttling, token tampering/expiry, and mass assignment.&lt;/td&gt;
&lt;td&gt;BDD scenarios return 403, 429, 400, &lt;code&gt;TOKEN_INVALID&lt;/code&gt;, &lt;code&gt;TOKEN_EXPIRED&lt;/code&gt;, and generic 202 as expected.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OWASP ASVS&lt;/td&gt;
&lt;td&gt;Security verification should be expressed as testable technical controls, not only policy statements.&lt;/td&gt;
&lt;td&gt;Authentication, token lifecycle, authorization, and privacy-preserving registration behavior are verified as executable tests.&lt;/td&gt;
&lt;td&gt;Backend BDD: 12 scenarios and 57 steps passed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OWASP Web Security Testing Guide&lt;/td&gt;
&lt;td&gt;Security testing should include misuse and invalid-use cases that reveal enumeration, weak defenses, and abuse of valid functionality.&lt;/td&gt;
&lt;td&gt;Duplicate registration, brute-force login, register burst, invalid token, expired token, and non-admin admin requests are tested directly.&lt;/td&gt;
&lt;td&gt;8 abuse paths in the penetration-testing evidence.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OWASP Abuse Case Cheat Sheet&lt;/td&gt;
&lt;td&gt;Abuse cases help convert attacker goals into concrete requirements and tests.&lt;/td&gt;
&lt;td&gt;The project defines attacker-style behaviors such as forged admin registration, token tampering, duplicate email enumeration, and unauthorized admin status changes.&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;pen-test-report.md&lt;/code&gt; and BDD feature files map abuse behavior to expected API responses.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitLab Application Security&lt;/td&gt;
&lt;td&gt;Security scanning should be integrated into the development workflow so findings are repeatable and visible during merge requests.&lt;/td&gt;
&lt;td&gt;SAST, dependency scanning, and secret detection are configured in FE and BE CI.&lt;/td&gt;
&lt;td&gt;FE pipeline 279116 and BE pipeline 279225 security analyzer jobs succeeded.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OWASP ZAP Baseline Scan&lt;/td&gt;
&lt;td&gt;Passive DAST scanning is suitable for a safe baseline assessment of deployed/staging web applications.&lt;/td&gt;
&lt;td&gt;The backend CI includes a &lt;code&gt;dast-zap-baseline&lt;/code&gt; job that produces HTML/JSON artifacts when run against staging.&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;.gitlab-ci.yml&lt;/code&gt; defines &lt;code&gt;zap-report.html&lt;/code&gt; and &lt;code&gt;zap-report.json&lt;/code&gt; artifacts.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cucumber / Gherkin BDD&lt;/td&gt;
&lt;td&gt;Requirements should be readable as executable specifications that validate actual software behavior.&lt;/td&gt;
&lt;td&gt;Registration, activation, and admin flows are written as Gherkin features and executed through Behave/Playwright.&lt;/td&gt;
&lt;td&gt;BE 3 features passed; FE BDD generation and discovery succeeded.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Playwright Test Isolation&lt;/td&gt;
&lt;td&gt;Browser contexts isolate state so tests do not leak cookies/session data into each other.&lt;/td&gt;
&lt;td&gt;FE BDD uses isolated browser/page state and API-backed setup for role-specific flows.&lt;/td&gt;
&lt;td&gt;3 Playwright BDD tests discovered and CI &lt;code&gt;e2e-bdd&lt;/code&gt; succeeded.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Locust Documentation&lt;/td&gt;
&lt;td&gt;Load tests should model user behavior with tasks, wait time, headless execution, and exportable statistics.&lt;/td&gt;
&lt;td&gt;Locust users model registration, admin dashboard, kegiatan, and QA workloads; commands produce CSV and HTML reports.&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;locustfile.py&lt;/code&gt; uses &lt;code&gt;HttpUser&lt;/code&gt;, &lt;code&gt;@task&lt;/code&gt;, &lt;code&gt;between&lt;/code&gt;, &lt;code&gt;on_start&lt;/code&gt;, &lt;code&gt;--headless&lt;/code&gt;, &lt;code&gt;--csv&lt;/code&gt;, and &lt;code&gt;--html&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Martin Fowler's Practical Test Pyramid&lt;/td&gt;
&lt;td&gt;A healthy test strategy keeps many lower-level tests while adding only targeted end-to-end/BDD tests for high-value flows.&lt;/td&gt;
&lt;td&gt;IR B5 does not replace existing unit/API tests; it adds focused BDD and security scenarios for critical journeys.&lt;/td&gt;
&lt;td&gt;65 backend regression tests passed in addition to 12 BDD scenarios.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Why These References Matter for GBM
&lt;/h3&gt;

&lt;p&gt;The references are not used as generic citations only. Each one changes how testing is applied in this project:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;OWASP Top 10, ASVS, WSTG, and Abuse Case guidance shift testing from happy-path verification to attacker-aware verification.&lt;/li&gt;
&lt;li&gt;GitLab Application Security shifts security testing from occasional manual review to repeatable MR evidence.&lt;/li&gt;
&lt;li&gt;Cucumber/Gherkin shifts business-critical behavior from scattered implementation knowledge to readable executable specifications.&lt;/li&gt;
&lt;li&gt;Playwright isolation prevents frontend BDD from becoming flaky due to leaked session state between admin and non-admin flows.&lt;/li&gt;
&lt;li&gt;Locust keeps stress testing realistic by modeling user roles and wait times instead of sending context-free requests.&lt;/li&gt;
&lt;li&gt;The Test Pyramid keeps the suite economically sane: unit/API tests remain broad, while BDD/E2E tests are targeted to the highest-risk workflows.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;References:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OWASP Top 10 2021: &lt;a href="https://owasp.org/Top10/2021/" rel="noopener noreferrer"&gt;https://owasp.org/Top10/2021/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;OWASP ASVS: &lt;a href="https://owasp.org/www-project-application-security-verification-standard/" rel="noopener noreferrer"&gt;https://owasp.org/www-project-application-security-verification-standard/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;OWASP Web Security Testing Guide, application misuse testing: &lt;a href="https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/10-Business_Logic_Testing/07-Test_Defenses_Against_Application_Misuse" rel="noopener noreferrer"&gt;https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/10-Business_Logic_Testing/07-Test_Defenses_Against_Application_Misuse&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;OWASP Abuse Case Cheat Sheet: &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Abuse_Case_Cheat_Sheet.html" rel="noopener noreferrer"&gt;https://cheatsheetseries.owasp.org/cheatsheets/Abuse_Case_Cheat_Sheet.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitLab SAST: &lt;a href="https://docs.gitlab.com/ee/user/application_security/sast/" rel="noopener noreferrer"&gt;https://docs.gitlab.com/ee/user/application_security/sast/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitLab Application Security detection: &lt;a href="https://docs.gitlab.com/user/application_security/detect/" rel="noopener noreferrer"&gt;https://docs.gitlab.com/user/application_security/detect/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;OWASP ZAP Baseline Scan: &lt;a href="https://www.zaproxy.org/docs/docker/baseline-scan/" rel="noopener noreferrer"&gt;https://www.zaproxy.org/docs/docker/baseline-scan/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Cucumber BDD overview: &lt;a href="https://cucumber.io/docs/guides/overview/" rel="noopener noreferrer"&gt;https://cucumber.io/docs/guides/overview/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Playwright test isolation: &lt;a href="https://playwright.dev/docs/browser-contexts" rel="noopener noreferrer"&gt;https://playwright.dev/docs/browser-contexts&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Locust documentation: &lt;a href="https://docs.locust.io/en/stable/" rel="noopener noreferrer"&gt;https://docs.locust.io/en/stable/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Locust configuration and report options: &lt;a href="https://docs.locust.io/en/stable/configuration.html" rel="noopener noreferrer"&gt;https://docs.locust.io/en/stable/configuration.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Martin Fowler, Practical Test Pyramid: &lt;a href="https://martinfowler.com/articles/practical-test-pyramid.html" rel="noopener noreferrer"&gt;https://martinfowler.com/articles/practical-test-pyramid.html&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Critique of Previous Testing and Quality Improvements
&lt;/h2&gt;

&lt;p&gt;This critique compares the condition before IR B5 More Testing existed with the final implemented state.&lt;/p&gt;

&lt;h3&gt;
  
  
  Critique 1: Critical flows were not represented as consolidated executable specifications
&lt;/h3&gt;

&lt;p&gt;Before IR B5, critical behavior such as registration, activation, login lockout, and admin approval was not presented as one readable executable specification for reviewers. The risk was not that the project had no tests at all; the risk was that the business-critical acceptance behavior was spread across implementation-level tests and was harder to review as user journeys.&lt;/p&gt;

&lt;p&gt;Final improvement: backend and frontend BDD now describe those journeys in Gherkin and execute them against real system behavior.&lt;/p&gt;

&lt;p&gt;Evidence:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Backend Behave: 3 features, 12 scenarios, 57 steps passed.&lt;/li&gt;
&lt;li&gt;Frontend Playwright BDD: 3 tests discovered; &lt;code&gt;e2e-bdd&lt;/code&gt; passed in pipeline 279116.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Critique 2: Security behavior was not presented as explicit abuse-case coverage
&lt;/h3&gt;

&lt;p&gt;Before IR B5, the security posture for this claim was not organized around attacker behavior. A reviewer could not quickly trace OWASP risks to endpoint-level expected responses.&lt;/p&gt;

&lt;p&gt;Final improvement: the penetration-testing evidence now maps attacker-style actions to concrete API behavior: non-admin access is rejected, lockout/rate limit is enforced, forged admin registration is rejected, tampered/expired tokens fail safely, and duplicate registration avoids account enumeration.&lt;/p&gt;

&lt;p&gt;Evidence:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;8 abuse paths documented and implemented.&lt;/li&gt;
&lt;li&gt;Expected responses include 403, 429, 400, &lt;code&gt;TOKEN_INVALID&lt;/code&gt;, &lt;code&gt;TOKEN_EXPIRED&lt;/code&gt;, and generic 202.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Critique 3: Security scanning was not consistently demonstrated as MR evidence for both FE and BE
&lt;/h3&gt;

&lt;p&gt;Before IR B5, security evidence was not presented as a complete MR-level story across frontend and backend.&lt;/p&gt;

&lt;p&gt;Final improvement: FE and BE now both show CI-level security analyzer execution. FE pipeline 279116 passed the security jobs, while BE pipeline 279225 passed SAST, dependency scanning, and secret detection.&lt;/p&gt;

&lt;p&gt;Evidence:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;FE pipeline 279116: &lt;code&gt;semgrep-sast&lt;/code&gt;, &lt;code&gt;gemnasium-dependency_scanning&lt;/code&gt;, and &lt;code&gt;secret_detection&lt;/code&gt; success.&lt;/li&gt;
&lt;li&gt;BE pipeline 279225: &lt;code&gt;semgrep-sast&lt;/code&gt;, &lt;code&gt;gemnasium-python-dependency_scanning&lt;/code&gt;, and &lt;code&gt;secret_detection&lt;/code&gt; success.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Critique 4: Stress testing was not tied to realistic GBM user behavior
&lt;/h3&gt;

&lt;p&gt;Before IR B5, stress testing evidence was not expressed as clear GBM user workloads tied to roles, endpoints, and operational scenarios.&lt;/p&gt;

&lt;p&gt;Final improvement: Locust now defines named workloads for semester-start registration, admin dashboard usage, authenticated kegiatan access, and mixed QA behavior.&lt;/p&gt;

&lt;p&gt;Evidence:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;RegistrationBurstUser&lt;/code&gt; models public registration load.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AdminDashboardUser&lt;/code&gt; models authenticated admin behavior.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;KegiatanStressTestUser&lt;/code&gt; models authenticated kegiatan/statistik/periode access.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GBMQualityAssuranceUser&lt;/code&gt; models a mixed backend API baseline.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Critique 5: Expected protection responses needed to be separated from real failures
&lt;/h3&gt;

&lt;p&gt;Before IR B5, high-load and abuse-case evidence could be misunderstood if every 429 response was treated as a failure. In this project, 429 can be the correct result because it means the rate limiter is protecting authentication or registration endpoints.&lt;/p&gt;

&lt;p&gt;Final improvement: BDD and Locust distinguish expected protection from unexpected failure.&lt;/p&gt;

&lt;p&gt;Evidence:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;BDD expects 429 for login lockout and register burst controls.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;RegistrationBurstUser&lt;/code&gt; treats 202 and 429 as acceptable outcomes for registration burst behavior.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Claim Boundaries
&lt;/h2&gt;

&lt;p&gt;This blog deliberately does not claim the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It does not claim that staging stress testing meets p95 below 500ms.&lt;/li&gt;
&lt;li&gt;It does not claim that stress tests should block every merge request.&lt;/li&gt;
&lt;li&gt;It does not claim that BDD replaces unit/API tests.&lt;/li&gt;
&lt;li&gt;It does not claim that security scanners prove the application has no vulnerabilities.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The actual claim is narrower and evidence-based: advanced testing tools are implemented, their outputs are understood, and their benefits are tied to concrete project data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The IR B5 More Testing claim is satisfied because:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Advanced tools are implemented and used: Behave, Playwright BDD, GitLab SAST, Dependency Scanning, Secret Detection, OWASP ZAP baseline, and Locust.&lt;/li&gt;
&lt;li&gt;The outputs are understood: 403 means access control is enforced, 429 means expected protection under abuse/load, 400 with token-specific codes means invalid activation is rejected safely, and security analyzer jobs provide repeatable MR evidence.&lt;/li&gt;
&lt;li&gt;The benefits are measurable: 12 backend BDD scenarios passed, 65 backend regression tests passed, frontend pipeline 279116 passed BDD/security/quality checks, and backend pipeline 279225 passed test, BDD, coverage, and security analyzer jobs.&lt;/li&gt;
&lt;li&gt;The work aligns with literature and current best practices: OWASP for abuse/security testing, GitLab for repeatable DevSecOps scanning, Cucumber for executable specifications, Playwright for isolated browser tests, Locust for user-behavior load modeling, and the Test Pyramid for balanced test economics.&lt;/li&gt;
&lt;li&gt;The critique is based on the project state before IR B5 implementation and the final state after implementation.&lt;/li&gt;
&lt;/ol&gt;

</description>
    </item>
    <item>
      <title>Optimizing Test Design Mutation Testing, ISP, and CFG in the GBIM Project</title>
      <dc:creator>Vincent Davis</dc:creator>
      <pubDate>Mon, 11 May 2026 07:12:12 +0000</pubDate>
      <link>https://dev.to/vincent_davis_7b6665836a9/optimizing-test-design-mutation-testing-isp-and-cfg-in-the-gbim-project-13d5</link>
      <guid>https://dev.to/vincent_davis_7b6665836a9/optimizing-test-design-mutation-testing-isp-and-cfg-in-the-gbim-project-13d5</guid>
      <description>&lt;p&gt;&lt;strong&gt;Vincent Davis Leonard&lt;/strong&gt; &lt;/p&gt;




&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;I applied three test design optimization techniques (Input Space Partitioning or ISP, Control Flow Graph or CFG Analysis, and Mutation Testing) to the four main features I manage in the GBIM project. These features include account registration, account activation via token, account verification by admin, and the approval or rejection of submissions. The results include 33 new tests in the backend, 3 commits in the frontend, an expanded mutation scope, and the addition of Stryker threshold enforcement to the CI pipeline.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tools and Methods Used
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Input Space Partitioning (ISP)
&lt;/h3&gt;

&lt;p&gt;ISP (Ammann &amp;amp; Offutt, &lt;em&gt;Introduction to Software Testing&lt;/em&gt;, 2016) is a technique that divides the input domain of a function into equivalence classes. These classes are groups of values expected to be treated similarly by the system. Instead of trying all combinations, we select one representative value per partition.&lt;/p&gt;

&lt;p&gt;I used the base-choice coverage strategy. We choose one valid value as a baseline and then vary one characteristic per test. This approach is efficient without falling into combinatorial explosion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tools used&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Manual analysis of the source code (&lt;code&gt;authentication/serializers.py&lt;/code&gt;, &lt;code&gt;RegisterForm.tsx&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Annotation &lt;code&gt;# ISP &amp;lt;characteristic&amp;gt;.&amp;lt;partition&amp;gt;&lt;/code&gt; in each test for traceability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Examples of partitioned characteristics for the Register feature&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Characteristic&lt;/th&gt;
&lt;th&gt;Partition&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Email&lt;/td&gt;
&lt;td&gt;valid, no &lt;code&gt;@&lt;/code&gt;, active duplicate, inactive duplicate, &amp;gt;254 char, whitespace&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Password&lt;/td&gt;
&lt;td&gt;&amp;lt;8 char, exactly 8 without digits, no uppercase, valid strong&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Role&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;KAPRODI&lt;/code&gt;, &lt;code&gt;GURU_BESAR&lt;/code&gt;, &lt;code&gt;ADMIN&lt;/code&gt; (blocked), invalid enum&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Activation Token&lt;/td&gt;
&lt;td&gt;valid fresh, expired, already used, malformed, missing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  2. Control Flow Graph (CFG) Analysis
&lt;/h3&gt;

&lt;p&gt;CFG (Ammann &amp;amp; Offutt, ch.7) represents the program execution flow as a graph where each node is a basic block and each edge is a conditional branch. From the CFG we identify &lt;strong&gt;prime paths&lt;/strong&gt; which are the shortest non-repeating paths through all nodes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Target module &lt;code&gt;_validate_transition&lt;/code&gt; (&lt;code&gt;pengajuan/services.py 66-75&lt;/code&gt;)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The actual code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="mi"&gt;66&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_validate_transition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;previous_status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="mi"&gt;67&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;     &lt;span class="nf"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;previous_status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ALLOWED_TRANSITIONS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="mi"&gt;68&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;         &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValidationError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="mi"&gt;69&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;             &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;                 &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="mi"&gt;71&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;                     &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Transisi status dari &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;previous_status&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; ke &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;new_status&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="mi"&gt;72&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;                     &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tidak diperbolehkan.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="mi"&gt;73&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;                 &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;74&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;             &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;         &lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CFG of this code (node = line of code, edge = execution flow)&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fljmwuxyz6esbxr3xkd63.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fljmwuxyz6esbxr3xkd63.png" alt=" " width="578" height="987"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Prime paths&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Condition&lt;/th&gt;
&lt;th&gt;Test&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1→2→3→5&lt;/td&gt;
&lt;td&gt;transition is not in &lt;code&gt;ALLOWED_TRANSITIONS&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;test_disetujui_to_menunggu_raises&lt;/code&gt;, &lt;code&gt;test_menunggu_to_menunggu_raises&lt;/code&gt;, etc&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1→2→4→5&lt;/td&gt;
&lt;td&gt;transition is in &lt;code&gt;ALLOWED_TRANSITIONS&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;test_menunggu_to_disetujui&lt;/code&gt;, &lt;code&gt;test_menunggu_to_ditolak&lt;/code&gt;, etc&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This state machine CFG has 4 legal transitions and 5+ illegal transitions that all must have tests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tools&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Manual source code analysis + Mermaid diagram (planned in the &lt;code&gt;cfg/&lt;/code&gt; folder)&lt;/li&gt;
&lt;li&gt;Annotation &lt;code&gt;# CFG: from_state→to_state&lt;/code&gt; in the tests&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  3. Mutation Testing
&lt;/h3&gt;

&lt;p&gt;Mutation testing (Jia &amp;amp; Harman, IEEE TSE 2011) measures the quality of a test suite by injecting small defects or mutants into the source code. Examples include changing &lt;code&gt;&amp;gt;&lt;/code&gt; to &lt;code&gt;&amp;gt;=&lt;/code&gt;, or removing a condition. The process then checks if the test suite detects it (meaning the mutant is "killed"). The mutation score is calculated by dividing the killed mutants by the total mutants.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tools&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Backend&lt;/strong&gt; &lt;code&gt;mutmut&lt;/code&gt; (Python) with operators including AOR, LCR, ROR, and statement deletion&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frontend&lt;/strong&gt; Stryker Mutator (JS/TS) with operators including arithmetic, logical, equality, string, and array&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both tools are complementary. The &lt;code&gt;mutmut&lt;/code&gt; tool is more aggressive in statement deletion, while Stryker is richer in JS/TS level operators.&lt;/p&gt;


&lt;h2&gt;
  
  
  Application to the Project and Evidence of Improvement
&lt;/h2&gt;
&lt;h3&gt;
  
  
  ISP Application
&lt;/h3&gt;

&lt;p&gt;Before this sprint, the &lt;code&gt;test_register_serializers.py&lt;/code&gt; test only covered the happy path and one or two errors. After the ISP audit, the following changes were made.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;New backend tests added&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;File&lt;/th&gt;
&lt;th&gt;New Partitions&lt;/th&gt;
&lt;th&gt;Count&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;test_register_serializers.py&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;email whitespace, email &amp;gt;254 char, inactive duplicate email, password exactly 8, password no digit, password no uppercase, password whitespace, role ADMIN blocked, role null, telephone invalid format&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;test_activation_views.py&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;token malformed, account already active&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;test_views_admin_account_verification.py&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;filter role invalid enum, filter status invalid enum, search no match, pagination beyond max&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;test_views_admin_account_verification_detail.py&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;approve AKTIF (idempotent), approve DITOLAK (reactivation), reject DITOLAK, reject non-existent, unauthorized non-admin&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;New frontend tests added&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;File&lt;/th&gt;
&lt;th&gt;New Partitions&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RegisterForm.test.tsx&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;API 429 rate limit response (ISP ApiError.status.429)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;useUpdateStatusPengajuan.test.ts&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;MENUNGGU to DITOLAK transition (CFG happy-path DITOLAK)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  CFG Application
&lt;/h3&gt;

&lt;p&gt;Previously, &lt;code&gt;StatusChangeService._validate_transition&lt;/code&gt; was only tested for 2 to 3 legal transitions. After the CFG analysis, I added tests for all 5 illegal transitions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fti71t9txomeb0px5wgfe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fti71t9txomeb0px5wgfe.png" alt=" " width="698" height="1265"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# CFG MENUNGGU to MENUNGGU (illegal self-loop)
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_validate_transition_menunggu_to_menunggu_raises&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;

&lt;span class="c1"&gt;# CFG DISETUJUI to MENUNGGU (illegal backward)
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_validate_transition_disetujui_to_menunggu_raises&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A total of 5 new CFG tests for illegal transitions were added along with annotations on the existing tests.&lt;/p&gt;

&lt;h3&gt;
  
  
  mutmut Scope Expansion
&lt;/h3&gt;

&lt;p&gt;Previously, the &lt;code&gt;pyproject.toml&lt;/code&gt; file only mutated &lt;code&gt;pengajuan/views/&lt;/code&gt; and &lt;code&gt;kegiatan/views/&lt;/code&gt;. Now it includes the following paths.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;paths_to_mutate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s"&gt;"pengajuan/views/views_admin.py"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"pengajuan/views/views_kaprodi.py"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"kegiatan/views/views_kegiatan.py"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"statistik_prodi/views.py"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"authentication/serializers.py"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c"&gt;# new addition&lt;/span&gt;
    &lt;span class="s"&gt;"authentication/services.py"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="c"&gt;# new addition&lt;/span&gt;
    &lt;span class="s"&gt;"authentication/views.py"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;         &lt;span class="c"&gt;# new addition&lt;/span&gt;
    &lt;span class="s"&gt;"pengajuan/services.py"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;           &lt;span class="c"&gt;# new addition&lt;/span&gt;
    &lt;span class="s"&gt;"pengajuan/serializers.py"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;        &lt;span class="c"&gt;# new addition&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Stryker Threshold Enforcement
&lt;/h3&gt;

&lt;p&gt;The following configuration was added to &lt;code&gt;stryker.config.mjs&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;thresholds&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;high&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;low&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;70&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means the frontend CI pipeline will automatically fail if the mutation score drops below 70 percent. This ensures the test quality does not regress.&lt;/p&gt;




&lt;h2&gt;
  
  
  Benefits, Concrete Data, and Best Practices
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Quantitative Data
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Number of BE tests (auth and pengajuan scope)&lt;/td&gt;
&lt;td&gt;~26 tests in target files&lt;/td&gt;
&lt;td&gt;+33 = ~59 tests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Number of FE tests (3 target files)&lt;/td&gt;
&lt;td&gt;97 tests&lt;/td&gt;
&lt;td&gt;+2 = 99 tests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mutmut scope (paths_to_mutate)&lt;/td&gt;
&lt;td&gt;4 paths (views only)&lt;/td&gt;
&lt;td&gt;9 paths (views, services, serializers)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stryker threshold FE&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;td&gt;break 70, high 80&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Documented ISP partitions (BE)&lt;/td&gt;
&lt;td&gt;~5 (implicit)&lt;/td&gt;
&lt;td&gt;28 explicit and annotated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CFG paths covered (StatusChangeService)&lt;/td&gt;
&lt;td&gt;2 to 3 legal&lt;/td&gt;
&lt;td&gt;4 legal and 5 illegal&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Connection to Literature
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;ISP by Ammann &amp;amp; Offutt (2016)&lt;/strong&gt;&lt;br&gt;
Ammann and Offutt define Input Space Partitioning as the division of an input domain into partitions where each must be represented by at least one test. The base-choice coverage strategy I used is their recommendation for balancing coverage with efficiency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mutation Testing by Jia &amp;amp; Harman (2011)&lt;/strong&gt;&lt;br&gt;
The survey by Jia and Harman shows that the mutation score is a more reliable predictor of test suite quality than statement coverage. They also documented that equivalent mutants (mutants that are semantically identical to the original code) are a major challenge. I document these cases when found.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Petrović &amp;amp; Ivanković (ICSE 2021) on Mutation Testing&lt;/strong&gt;&lt;br&gt;
This paper reports the results of deploying mutation testing at scale at Google. Developers who receive mutation testing feedback consistently write better tests. The Stryker threshold I implemented follows this principle by maintaining the mutation score as an automatic quality gate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Meszaros, xUnit Test Patterns (2007)&lt;/strong&gt;&lt;br&gt;
Test smells such as Assertion Roulette (multiple assertions without messages) and Obscure Test (tests that are difficult to understand) are anti-patterns I avoid. Every new test has one clear assertion and an ISP or CFG comment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Google Testing Blog on Mutation Testing at Google (2018)&lt;/strong&gt;&lt;br&gt;
Google recommends focusing on killed mutants per time rather than the raw mutation score. This means prioritizing mutants in frequently changing code, which aligns with the auth and pengajuan features in this sprint.&lt;/p&gt;

&lt;h3&gt;
  
  
  Best Practices Followed
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Each-choice minimum with base-choice for crucial parameters&lt;/strong&gt; (Ammann &amp;amp; Offutt recommendation)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mutation score as a quality gate rather than an optional metric&lt;/strong&gt; (Google engineering practice)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test isolation via &lt;code&gt;override_settings&lt;/code&gt; and &lt;code&gt;locmem&lt;/code&gt; cache&lt;/strong&gt; for rate limiter tests to avoid flakiness&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Annotation-based traceability&lt;/strong&gt; (&lt;code&gt;# ISP&lt;/code&gt;, &lt;code&gt;# CFG&lt;/code&gt;) to allow coverage auditing without reading all the code&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Critique of Previous Testing and Measurable Improvements
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Anti-Patterns Found in the Old Test Suite
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Anti-Pattern 1 Happy-Path-Only Register Serializer Test
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Location&lt;/strong&gt; &lt;code&gt;authentication/tests/test_register_serializers.py&lt;/code&gt; (before this sprint)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt; The registration test only verified that valid data passed the serializer. There were no tests for the following scenarios.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Passwords with a length of exactly 7 (boundary condition that should fail) versus exactly 8 (should pass)&lt;/li&gt;
&lt;li&gt;Emails that are already registered but not yet activated (which behave differently from active ones)&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;ADMIN&lt;/code&gt; role which should not be able to self-register&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why this is weak&lt;/strong&gt; A mutant changing &lt;code&gt;len(password) &amp;lt; 8&lt;/code&gt; to &lt;code&gt;len(password) &amp;lt;= 8&lt;/code&gt; or &lt;code&gt;len(password) &amp;lt; 7&lt;/code&gt; would survive because no test could distinguish the difference. This is a classic Boundary Value Analysis gap based on Myers' &lt;em&gt;The Art of Software Testing&lt;/em&gt; (1979).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix&lt;/strong&gt; Added &lt;code&gt;test_password_exactly_seven_chars_invalid&lt;/code&gt;, &lt;code&gt;test_email_already_registered_inactive&lt;/code&gt;, and &lt;code&gt;test_role_admin_cannot_register&lt;/code&gt; with the annotation &lt;code&gt;# ISP password.length_boundary&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Anti-Pattern 2 StatusChangeService Did Not Test Illegal Transitions
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Location&lt;/strong&gt; &lt;code&gt;pengajuan/tests/test_services.py&lt;/code&gt; (before this sprint)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt; There were only tests for legal transitions (MENUNGGU to DISETUJUI, and MENUNGGU to DITOLAK). There were no tests verifying that backward transitions (DISETUJUI to MENUNGGU) or self-loops (MENUNGGU to MENUNGGU) raise an exception.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why this is weak&lt;/strong&gt; A mutant removing one condition in the &lt;code&gt;ALLOWED_TRANSITIONS&lt;/code&gt; dictionary would survive. A state machine that is not tested exhaustively could allow status transitions that corrupt data integrity.&lt;/p&gt;

&lt;p&gt;Following the principles from Meszaros (&lt;em&gt;xUnit Test Patterns&lt;/em&gt;), tests must verify error behavior just as rigorously as happy behavior.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix&lt;/strong&gt; Added 5 CFG tests for illegal transitions with assertions that ensure exceptions are raised.&lt;/p&gt;

&lt;h4&gt;
  
  
  Anti-Pattern 3 Frontend Tests Did Not Cover API Error Variants
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Location&lt;/strong&gt; &lt;code&gt;tests/features/authentication/components/RegisterForm.test.tsx&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt; The registration form tests only mocked the success scenario (201) and generic errors. There were no tests for the following situations.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP 429 rate limit response which should display a throttling message&lt;/li&gt;
&lt;li&gt;HTTP 400 with field-specific errors which should map to the correct fields&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why this is weak&lt;/strong&gt; A Stryker mutant changing the HTTP status check condition would survive. This is also an Over-Mocked Service smell according to Meszaros, as overly generic mocks do not exercise real branch logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix&lt;/strong&gt; Added &lt;code&gt;test_register_form_shows_rate_limit_error&lt;/code&gt; with the annotation &lt;code&gt;// ISP ApiError.status.429&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Measurable Improvements (Before and After)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;th&gt;Delta&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Annotated ISP partitions&lt;/td&gt;
&lt;td&gt;0 (implicit)&lt;/td&gt;
&lt;td&gt;28 (explicit)&lt;/td&gt;
&lt;td&gt;+28&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Covered CFG illegal transitions&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;+5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mutmut scope (auth and pengajuan)&lt;/td&gt;
&lt;td&gt;0 paths&lt;/td&gt;
&lt;td&gt;5 new paths&lt;/td&gt;
&lt;td&gt;baseline capture enabled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stryker threshold FE&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;td&gt;break 70, high 80&lt;/td&gt;
&lt;td&gt;active CI guard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test methods for auth and pengajuan BE&lt;/td&gt;
&lt;td&gt;~26&lt;/td&gt;
&lt;td&gt;~59&lt;/td&gt;
&lt;td&gt;+33&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test methods FE (3 target files)&lt;/td&gt;
&lt;td&gt;97&lt;/td&gt;
&lt;td&gt;99&lt;/td&gt;
&lt;td&gt;+2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Connection to Industry Standards
&lt;/h3&gt;

&lt;p&gt;Google researchers (Petrović et al., ICSE 2021) found that mutation testing is most effective when integrated into the developer workflow as automated feedback rather than just a final report. The Stryker threshold I set implements this pattern by automatically blocking any merge request to staging if the mutation score regresses.&lt;/p&gt;

&lt;p&gt;The Stryker Mutator whitepaper (2023) recommends setting &lt;code&gt;coverageAnalysis&lt;/code&gt; to &lt;code&gt;"perTest"&lt;/code&gt; (which is already active in the config) to isolate mutants to the specific tests that cover them. This reduces false positives and execution time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Commit Links
&lt;/h2&gt;

&lt;h3&gt;
  
  
  BE-GBM MR !158
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Commit&lt;/th&gt;
&lt;th&gt;Message&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;b7564fc5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;chore(testing) expand mutmut scope to authentication and pengajuan services&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0c774595&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[GREEN] test(auth) add ISP partitions for register serializer, activation, and admin verification&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;a2def037&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[GREEN] test(pengajuan) add CFG prime path coverage for StatusChangeService state machine&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;MR Link:&lt;/strong&gt; &lt;code&gt;[https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2026/kelas-d/group1-gb/be-gbm/-/merge_requests/158]&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  fe-gbm MR !142
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Commit&lt;/th&gt;
&lt;th&gt;Message&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;f18590fe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;chore(testing) enforce Stryker mutation threshold at 80% high and 70% break&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;42d9b028&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[GREEN] test(auth) add ISP partitions for RegisterForm and useActivation hook&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;19328728&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[GREEN] test(pengajuan) add CFG branch coverage for useUpdateStatusPengajuan&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;MR Link:&lt;/strong&gt; &lt;code&gt;[https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2026/kelas-d/group1-gb/fe-gbm/-/merge_requests/142]&lt;/code&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Ammann, P. &amp;amp; Offutt, J. (2016). &lt;em&gt;Introduction to Software Testing&lt;/em&gt; (2nd ed.). Cambridge University Press. (ISP ch.6, Graph Coverage ch.7).&lt;/li&gt;
&lt;li&gt;Jia, Y. &amp;amp; Harman, M. (2011). "An Analysis and Survey of the Development of Mutation Testing." &lt;em&gt;IEEE Transactions on Software Engineering&lt;/em&gt;, 37(5), 649-678.&lt;/li&gt;
&lt;li&gt;Petrović, G., Ivanković, M., Fraser, G., &amp;amp; Just, R. (2021). "Does Mutation Testing Improve Testing Practices?" &lt;em&gt;ICSE 2021&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Petrović, G. &amp;amp; Ivanković, M. (2018). "State of Mutation Testing at Google." &lt;em&gt;Google Testing Blog&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Meszaros, G. (2007). &lt;em&gt;xUnit Test Patterns Refactoring Test Code&lt;/em&gt;. Addison-Wesley.&lt;/li&gt;
&lt;li&gt;Stryker Mutator. (2023). "Mutation Testing in Practice." &lt;em&gt;stryker-mutator.io&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Myers, G.J. (1979). &lt;em&gt;The Art of Software Testing&lt;/em&gt;. Wiley. (Boundary Value Analysis).&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>cicd</category>
      <category>computerscience</category>
      <category>softwareengineering</category>
      <category>testing</category>
    </item>
  </channel>
</rss>
