# Testing MVC-Starter This project now supports a dev-only Classic ASP test harness built with `aspunit`. ## Scope - Production app: `public/` - Dev-only test app: `tests/` - Test framework: `tests/aspunit/` The `tests/` IIS application assumes the repository layout keeps `tests/`, `public/`, `core/`, and `app/` as sibling directories. ## File Inventory | Type | Path | Purpose | | ---- | ---- | ------- | | Create | `tests/web.config` | IIS/default-document config for the isolated test app | | Create | `tests/unit/web.config` | Mirrored config for nested unit pages that load config-aware code | | Create | `tests/component/web.config` | Mirrored config for nested component pages that load config-aware code | | Create | `tests/integration/web.config` | Mirrored config for nested integration pages that load config-aware code | | Create | `tests/sync-webconfigs.vbs` | Utility script to mirror `tests/web.config` into nested test folders | | Create | `tests/run-tests.cmd` | Windows helper to sync configs and open the test runner URL | | Create | `tests/bootstrap.asp` | Shared test bootstrap and runtime reset helpers | | Create | `tests/PlainRunnerTheme.asp` | Local runner theme that removes CDN dependence from the test UI | | Create | `tests/support/HttpCaptureHelpers.asp` | Shared HTTP capture helpers for rendered-page assertions | | Create | `tests/test-manifest.asp` | Single source of truth for registered test pages | | Create | `tests/run-all.asp` | Browser runner that aggregates all test pages | | Vendor | `tests/aspunit/Lib/*` | Upstream aspunit framework files | | Vendor | `tests/aspunit/LICENSE-MIT` | Upstream aspunit license for vendored third-party code | | Create | `tests/unit/TestHelpers.asp` | Deterministic helper-function unit tests | | Create | `tests/unit/TestControllerRegistry.asp` | Controller whitelist/format unit tests | | Create | `tests/component/TestHomeController.asp` | Controlled component-level controller test | | Create | `tests/integration/TestMvcDispatch.asp` | Narrow router/dispatch smoke test | | Create | `tests/integration/TestRoutes.asp` | Route-helper/config integration coverage | | Create | `tests/integration/TestConfigSettings.asp` | Nested config and fallback behavior coverage | | Create | `tests/integration/TestRenderedOutput.asp` | Production-page output assertions through safe HTTP capture | | Create | `tests/integration/TestSharedLayout.asp` | Shared header/footer/layout assertions against rendered production pages | | Reference | `public/web.config` | Source of mirrored config keys for the test app | | Reference | `core/helpers.asp` | Helper functions and config-loading behavior under test | | Reference | `core/mvc.asp` | Dispatcher behavior used by the smoke test | | Reference | `core/lib.ControllerRegistry.asp` | Whitelist behavior under test | | Verify | `public/` site | Confirm production app exposes no test routes/pages | ## IIS Setup 1. Keep the existing production IIS app rooted at `public/`. 2. Create a separate development-only IIS application rooted at `tests/`. 3. Enable Classic ASP for that IIS app. 4. Ensure parent paths are allowed for the `tests/` app. This repo ships `tests/web.config` with `enableParentPaths="true"` because the bootstrap and integration pages include sibling files from `../core/` and `../app/`. 5. Browse to the `tests/` app root or directly to `run-all.asp`. 6. If you change `tests/web.config`, run `cscript //nologo tests\sync-webconfigs.vbs` to refresh the nested copies used by the unit, component, and integration pages. 7. If your production app is not served from the same host root as the `tests/` app, set `ProductionAppBaseUrl` in `tests/web.config` and re-run the sync script so rendered-output tests know where to send HTTP requests. Example: `http://localhost/` for a root site, or `http://localhost/MyClassicApp/` for a virtual-directory app. 8. To sync configs and open the suite in one step on Windows, run `tests\run-tests.cmd` with an optional runner URL argument. Example layout: - Production: `http://localhost/` - Tests: `http://localhost/tests-dev/` ## How It Works - `tests/run-all.asp` includes the aspunit library and the manifest. - `tests/run-all.asp` also applies `PlainRunnerTheme.asp`, a local runner theme that avoids the upstream CDN dependency in aspunit’s default UI. - `tests/test-manifest.asp` explicitly registers each test page. - `tests/bootstrap.asp` provides the shared runtime setup: - helper/config access - controller registry access - router reset - `tests/support/HttpCaptureHelpers.asp` provides safe HTTP-based page capture for rendered output assertions against the production app. The integration test page includes `core/mvc.asp` directly because that is the only first-wave test that needs dispatcher behavior. Because `GetAppSetting()` uses `Server.MapPath("web.config")`, nested test folders also need a mirrored `web.config` alongside the executing test pages that rely on config-aware runtime files. Use `tests/sync-webconfigs.vbs` after changing `tests/web.config`. The manifest is manual by design. There is no filesystem auto-discovery. ## Running Tests Open the browser runner: Browse to `run-all.asp` within the `tests/` IIS application, for example: ```text http://localhost/tests-dev/run-all.asp ``` aspunit renders a UI in runner mode and loads each registered page with `?task=test` behind the scenes. On Windows you can also use: ```bat tests\run-tests.cmd ``` Or with an explicit runner URL: ```bat tests\run-tests.cmd http://localhost:8085/run-all.asp ``` ## Adding a New Test Page 1. Choose the right folder: - `tests/unit/` for deterministic helper or registry tests - `tests/component/` for direct controller/object tests with controlled setup - `tests/integration/` for narrow runtime smoke coverage, config behavior, or rendered-page capture - shared layout assertions belong here too, because they verify rendered production responses rather than isolated helper behavior 2. Create a new `.asp` file that: - includes `../aspunit/Lib/ASPUnit.asp` - includes `../bootstrap.asp` - registers one or more modules with `ASPUnit.AddModule(...)` - calls `ASPUnit.Run()` 3. Add the page path to `tests/test-manifest.asp`. 4. Reload `run-all.asp`. ## First-Pass Isolation Policy - Unit tests should avoid mutating globals. - Registry tests should inspect current behavior, not expand the production whitelist. - Component tests should reset touched singleton/controller state in setup/teardown. - Dispatch smoke tests should initialize fresh route state before each run. ## What Not To Unit Test - Full rendered page markup for shared-layout pages unless you add reliable output-capture support. - Production IIS rewrite behavior from `public/`. - Broad end-to-end request flows through the production site root. - Config-dependent behavior that requires machine-specific production values unless you first mirror safe test values into `tests/web.config`. - Internet access as a requirement for the runner UI. The local theme removes the upstream CDN dependency for first-wave execution. ## Validation Checklist - `run-all.asp` loads in the separate `tests/` IIS app. - All manifest pages appear in the runner. - Helper, registry, component, and integration suites all execute. - Route-helper/config integration assertions execute from the same isolated IIS app. - Rendered-page capture assertions can verify production HTML and status codes without polluting aspunit JSON responses. - Shared layout assertions can verify navbar, asset links, titles, and footer script presence across production-rendered pages. - Re-running the suite produces stable results. - The production site under `public/` still exposes no test runner pages or test routes. ## Limitations - This harness runs only inside IIS/Classic ASP; it is not intended for Linux execution. - The repo’s production runtime is still configured via `public/web.config`; the test app uses a minimal mirrored config in `tests/web.config`. - If the narrow bootstrap is not sufficient for future smoke tests, broaden only the test bootstrap first before considering production runtime changes.