Environment variables
Every Precept setting can be set from the environment. This page is the complete list, generated by
hand from the settings classes themselves — PreceptSettings, the module settings, and the three
reporters' — and it is the reference a pipeline is written against.
- The rule
- Value formats
- The run
- Filter
- Web
- Api
- Assertions
- Grpc
- TestData
- Reqnroll
- ConnectionStrings
- Reporting
- Reporting:ReportPortal
- Reporting:Teams
- Reporting:AzureDevOps
- Sections of your own
- Test data values: a second namespace
- Variables Precept reads but does not own
- What has no variable
- Working with them
The rule#
PreceptSettings.Load builds its configuration from three sources, each overriding the last:
precept.json → precept.{environment}.json → PRECEPT_* environment variables
The variable name is the configuration key, prefixed with PRECEPT_, with every : written as a
double underscore:
| Configuration key | Variable |
|---|---|
MaxParallelism |
PRECEPT_MAXPARALLELISM |
Web:Headless |
PRECEPT_WEB__HEADLESS |
Reporting:Teams:WebhookUrl |
PRECEPT_REPORTING__TEAMS__WEBHOOKURL |
Names are case-insensitive: PRECEPT_WEB__HEADLESS and Precept_Web__Headless are the same
variable. The __ is not decoration — .NET's environment provider rewrites it to : before
matching, which is the only way to express a nested key in a name that has to be a valid
environment variable.
PRECEPT_ is a namespace with an owner. Everything carrying that prefix is stripped of it and
bound as a settings key, whether it names a real setting or not. Do not use it for a variable of
your own — a pipeline's scratch values, a script's working state — because a name that happens to
collide with a real key changes the run and nothing says so.
Value formats#
| Type | Accepts | Rejects |
|---|---|---|
| Boolean | true, True, false, False |
1, 0, yes, no — see below |
| Integer | 8, -1 |
anything non-numeric |
| Enum | the member name, any casing: Class, test, FailureOrFlaky |
a number |
| String | anything, including empty | — |
| Dictionary | one variable per entry; the last segment is the key | — |
| List | one variable per element, indexed from zero | — |
A boolean must be spelled out. The binder uses bool.Parse, and 1 is not a boolean to it —
it fails the run before a test starts, not quietly:
Unhandled exception. System.InvalidOperationException: Failed to convert configuration value '1'
at 'IsContinuousIntegration' to type 'System.Boolean'.
Worth knowing because a CI system that writes 1 for a checkbox is not unusual, and because
CI=1 — the one variable Precept reads for its value rather than binding — does work.
A dictionary entry is a variable of its own, and the key is whatever follows the last __:
PRECEPT_API__DEFAULTHEADERS__X-TENANT=acme # Api:DefaultHeaders["X-Tenant"]
PRECEPT_REPORTING__TEAMS__FACTS__BRANCH=main # Reporting:Teams:Facts["Branch"]
A list element is indexed:
PRECEPT_TESTDATA__FILES__0=testdata.json
PRECEPT_TESTDATA__FILES__1=vehicles.json
An empty value is a value. PRECEPT_FILTER__EXCLUDE= does not mean "the pipeline has no
opinion"; it sets the exclude expression to empty and so overrides whatever
precept.{environment}.json asked for. Unset the variable rather than blanking it.
The run#
Bound onto PreceptSettings itself, so these have no section in their name.
| Variable | Default | What it does |
|---|---|---|
PRECEPT_ENVIRONMENT |
local |
The environment, and so which precept.{env}.json overlay loads. Read directly rather than through the binder — see below. |
PRECEPT_ISCONTINUOUSINTEGRATION |
detected | Whether this run counts as a build agent's. Decides whether CI-only reporters start at all. |
PRECEPT_MAXPARALLELISM |
processor count | Units of work in flight at once. 0 or less means the processor count. A ceiling, not a target — a run cannot exceed the units it has. |
PRECEPT_PARALLELSCOPE |
Class |
Class or Test. What one unit of parallel work is. |
PRECEPT_RUNTIMEOUTMINUTES |
720 |
How long the whole run may take before what is still running is cut off and the rest is reported as not run. 0 removes the limit. Not enforced under a debugger. |
PRECEPT_DEFAULTTIMEOUTMILLISECONDS |
0 |
Per-test timeout for tests with no [Timeout]. 0 — the default — sets none; the run limit above is what bounds a run. Not enforced under a debugger. |
PRECEPT_DEFAULTRETRIES |
0 |
Reruns of a failing test with no [Retry]. 0 reruns nothing; 2 means a test may run three times in all. |
PRECEPT_ARTIFACTDIRECTORY |
PreceptArtifacts |
Where screenshots, traces and attachments are written. Relative to the test binary unless rooted. Keep it short — Windows caps a full path at 260 characters, past which the artifact is written but the TRX writer's copy of it fails. |
Filter#
Tests this run pretends were never written: absent from the run, from the report and from a test
explorer's tree, rather than reported as skipped. This is the environment's own policy, and it is
applied in discovery — --precept-filter cannot select a test it has removed.
| Variable | Default | What it does |
|---|---|---|
PRECEPT_FILTER__INCLUDE |
unset | Run only tests matching this expression. |
PRECEPT_FILTER__EXCLUDE |
unset | Remove tests matching it, whatever Include says. |
Both are single expressions rather than lists, precisely so a later source can replace one outright.
The expression language is the same one --precept-filter
takes.
Web#
| Variable | Default | What it does |
|---|---|---|
PRECEPT_WEB__BASEURL |
unset | Base address relative navigations resolve against. |
PRECEPT_WEB__BROWSER |
chromium |
chromium, firefox or webkit. |
PRECEPT_WEB__ARGS |
unset | Extra command-line arguments for the browser executable, as one command line: --no-sandbox --disable-dev-shm-usage. Split on whitespace outside quotes, and either quote character groups — --user-agent='Mozilla/5.0 (X11)' is one argument. Passed to the browser process, so it applies to the whole run and not to one test; the flags are the engine's own and an unrecognised one is ignored rather than reported. |
PRECEPT_WEB__HEADLESS |
true |
Run without a visible browser window. |
PRECEPT_WEB__TIMEOUTMILLISECONDS |
30000 |
Default timeout for element and navigation waits. |
PRECEPT_WEB__ASSERTIONTIMEOUTMILLISECONDS |
5000 |
How long a web-first assertion retries. Separate from the above on purpose: an action waiting half a minute is patience, an assertion doing it is a suite that takes half a minute to say what broke. |
PRECEPT_WEB__SLOWMOMILLISECONDS |
0 |
Slow each Playwright operation down, for debugging. |
PRECEPT_WEB__RESOLUTION |
unset | The viewport as one value: 720p, 900p, 1080p, 1440p, 2160p, the aliases hd, fhd, qhd, uhd, 4k, or a pair such as 1366x768. Decides the viewport outright when set, so a pipeline naming one need not also clear the two numbers below. An unrecognised value fails the run rather than picking a size for you. |
PRECEPT_WEB__VIEWPORTWIDTH |
1280 |
Viewport width in pixels. Used when no resolution is named. |
PRECEPT_WEB__VIEWPORTHEIGHT |
800 |
Viewport height in pixels. Used when no resolution is named. |
PRECEPT_WEB__SCREENSHOTONFAILURE |
true |
Capture a screenshot when a test fails. |
PRECEPT_WEB__TRACEONFAILURE |
true |
Record a Playwright trace, attached on failure. |
PRECEPT_WEB__VIDEOONFAILURE |
false |
Record a video of each test, attached on failure. |
Api#
| Variable | Default | What it does |
|---|---|---|
PRECEPT_API__BASEURL |
unset | Base address relative request paths resolve against. |
PRECEPT_API__TIMEOUTMILLISECONDS |
30000 |
Request timeout. |
PRECEPT_API__LOGPAYLOADS |
true |
Attach full request and response bodies to the test log. |
PRECEPT_API__DEFAULTHEADERS__<NAME> |
none | A header sent with every request. One variable per header. |
PRECEPT_API__XMLNAMESPACES__<PREFIX> |
none | A namespace URI an XPath prefix resolves to when reading an XML response. One variable per prefix. |
Assertions#
Read only by assertions that wait — those built with Assert.Eventually. An assertion over a value
already in hand is decided immediately and reads none of this.
| Variable | Default | What it does |
|---|---|---|
PRECEPT_ASSERTIONS__TIMEOUTMILLISECONDS |
5000 |
How long a waiting assertion keeps re-reading its value. |
PRECEPT_ASSERTIONS__POLLINTERVALMILLISECONDS |
100 |
How long to wait between attempts. |
Grpc#
| Variable | Default | What it does |
|---|---|---|
PRECEPT_GRPC__ADDRESS |
unset | The service address. |
PRECEPT_GRPC__DEADLINEMILLISECONDS |
30000 |
Per-call deadline. |
PRECEPT_GRPC__ALLOWINSECURE |
true |
Permit an unencrypted http:// channel. |
PRECEPT_GRPC__MAXRECEIVEMESSAGESIZE |
4194304 |
Largest message accepted, in bytes. |
PRECEPT_GRPC__LOGMESSAGES |
true |
Attach request and response messages to the test log. |
TestData#
These configure the module. The data itself lives in its own files, and has a namespace of its own.
| Variable | Default | What it does |
|---|---|---|
PRECEPT_TESTDATA__DIRECTORY |
. |
Directory the data files are read from, relative to the test binary unless rooted. |
PRECEPT_TESTDATA__FILES__<n> |
testdata.json |
Data files, in increasing order of precedence. One variable per element. |
PRECEPT_TESTDATA__ENVIRONMENTOVERLAY |
true |
Load the {file}.{environment}.json overlay beside each file. |
PRECEPT_TESTDATA__LEASETIMEOUTMILLISECONDS |
30000 |
How long LeaseAsync waits for a pooled item. Overridable per pool. |
Reqnroll#
Read as the first scenario starts, by Precept.Reqnroll's runtime plugin. The section's other
keys — FEATURELANGUAGE, ALLOWROWTESTS, ADDNONPARALLELIZABLEMARKERFORTAGS,
ALLOWDEBUGGENERATEDFILES, DISABLEFRIENDLYTESTNAMES — shape the generated code and are read from
the project's precept.json while the feature files compile, so a variable cannot reach them; see
configuring Reqnroll.
| Variable | Default | What it does |
|---|---|---|
PRECEPT_REQNROLL__BINDINGCULTURE |
unset | Culture step arguments are converted with. Unset means the feature language. |
PRECEPT_REQNROLL__STOPATFIRSTERROR |
false |
Skip the remaining steps of a scenario once one has failed. |
PRECEPT_REQNROLL__MISSINGORPENDINGSTEPSOUTCOME |
Pending |
Outcome of a scenario with a missing or pending step: Pending, Inconclusive, Ignore or Error. |
PRECEPT_REQNROLL__OBSOLETEBEHAVIOR |
Warn |
What a step bound to an [Obsolete] definition does: None, Warn, Pending or Error. |
PRECEPT_REQNROLL__TRACESUCCESSFULSTEPS |
true |
Write every passing step to the test's log. |
PRECEPT_REQNROLL__TRACETIMINGS |
false |
Log how long each step took. |
PRECEPT_REQNROLL__MINTRACEDDURATIONMILLISECONDS |
100 |
Shortest step duration worth a timing line. |
PRECEPT_REQNROLL__STEPDEFINITIONSKELETONSTYLE |
CucumberExpressionAttribute |
Shape of the skeleton logged for a step with no definition. |
PRECEPT_REQNROLL__BINDINGASSEMBLIES__<n> |
none | Assemblies searched for bindings besides the test assembly. One variable per element. |
ConnectionStrings#
One variable per named connection, the name being whatever follows the last __. Db.Query(...)
uses Default unless told otherwise.
PRECEPT_CONNECTIONSTRINGS__DEFAULT='Host=db.stage;Database=app;Username=tests;Password=…'
PRECEPT_CONNECTIONSTRINGS__WAREHOUSE='Server=…'
A connection string holds a password, so this is a variable and not a line in precept.json.
Reporting#
The pipeline itself. What each reporter does with the events is in its own subsection below.
| Variable | Default | What it does |
|---|---|---|
PRECEPT_REPORTING__ENABLED |
true |
Turns the whole pipeline off. Nothing is constructed and no queue is started. |
PRECEPT_REPORTING__CIONLY |
unset | Overrides where every reporter runs. true confines the lot to a build agent, false lets the lot run anywhere. Unset, each reporter decides, and the three shipped ones are CI-only. |
PRECEPT_REPORTING__QUEUECAPACITY |
4096 |
Events that may wait for one reporter before further ones are dropped. Drops are counted and reported at the end of the run. |
PRECEPT_REPORTING__SHUTDOWNTIMEOUTSECONDS |
60 |
How long the run waits, after the last test, for reporters to finish sending. |
PRECEPT_REPORTING__MAXFAILURES |
10 |
How many times one reporter may throw before it is dropped for the rest of the run. A destination that is down should cost one message, not one per test. |
PRECEPT_REPORTING__MAXTRACKEDFAILURES |
100 |
How many failed tests the run summary carries. The failure count is exact either way. |
PRECEPT_REPORTING__CIONLY=false is the single variable that makes a laptop report for one run.
From there a missing API key is an error, because you have just asked that machine to report.
Reporting:ReportPortal#
| Variable | Default | What it does |
|---|---|---|
PRECEPT_REPORTING__REPORTPORTAL__ENABLED |
true |
Report to ReportPortal at all. |
PRECEPT_REPORTING__REPORTPORTAL__CIONLY |
true |
Report only from a build agent. |
PRECEPT_REPORTING__REPORTPORTAL__ENDPOINT |
unset | Base address, without the /api path. |
PRECEPT_REPORTING__REPORTPORTAL__PROJECT |
unset | The project the launch belongs to. |
PRECEPT_REPORTING__REPORTPORTAL__APIKEY |
unset | Credential. The account the launch is reported under. |
PRECEPT_REPORTING__REPORTPORTAL__LAUNCHNAME |
assembly name | Name of the launch. |
PRECEPT_REPORTING__REPORTPORTAL__DESCRIPTION |
a line naming the environment | Description on the launch. On an Azure DevOps agent a link to the build is appended either way. |
PRECEPT_REPORTING__REPORTPORTAL__LAUNCHMODE |
DEFAULT |
DEFAULT for a launch everyone sees, DEBUG for one kept out of the project's statistics. |
PRECEPT_REPORTING__REPORTPORTAL__ATTRIBUTES__<KEY> |
none | An attribute on the launch. One variable per attribute; the environment is added automatically. |
PRECEPT_REPORTING__REPORTPORTAL__REPORTCATEGORIESASATTRIBUTES |
true |
Report each test's tags as attributes of its item. |
PRECEPT_REPORTING__REPORTPORTAL__LOGMESSAGES |
true |
Send the lines a test logged as log entries. |
PRECEPT_REPORTING__REPORTPORTAL__ATTACHARTIFACTS |
true |
Upload screenshots, traces and other captured files. |
PRECEPT_REPORTING__REPORTPORTAL__ATTACHONSUCCESS |
false |
Attach artifacts of passing tests too. |
PRECEPT_REPORTING__REPORTPORTAL__MAXATTACHMENTBYTES |
8388608 |
Largest artifact uploaded. A trace of a long scenario runs to tens of megabytes and is rarely what anyone opens from a dashboard. |
PRECEPT_REPORTING__REPORTPORTAL__RERUN |
false |
Report this launch as a rerun, so ReportPortal merges it into the previous one. |
PRECEPT_REPORTING__REPORTPORTAL__RERUNOF |
unset | Name or UUID of the launch being rerun. |
PRECEPT_REPORTING__REPORTPORTAL__TIMEOUTSECONDS |
60 |
How long any single call may take. |
Reporting:Teams#
| Variable | Default | What it does |
|---|---|---|
PRECEPT_REPORTING__TEAMS__ENABLED |
true |
Post at all. |
PRECEPT_REPORTING__TEAMS__CIONLY |
true |
Post only from a build agent. |
PRECEPT_REPORTING__TEAMS__WEBHOOKURL |
unset | Credential. The channel's incoming webhook, from its Workflows connector. Anyone holding it can post to the channel. |
PRECEPT_REPORTING__TEAMS__TITLE |
assembly name | Heading on the card. |
PRECEPT_REPORTING__TEAMS__VARIANT |
Summary |
Card layout: Summary, Compact, Detailed (adds the failures), or Pipeline (adds the build). |
PRECEPT_REPORTING__TEAMS__NOTIFYON |
Always |
Always, Failure, or FailureOrFlaky — the last of which also posts when a test only passed on a retry. |
PRECEPT_REPORTING__TEAMS__IMAGEURL |
unset | An image for the card — a pipeline status badge, a logo. Must be reachable by every reader's Teams client without signing in. |
PRECEPT_REPORTING__TEAMS__IMAGEPLACEMENT |
Thumbnail |
Where it goes: Thumbnail, Banner, or None to drop it without losing the URL. |
PRECEPT_REPORTING__TEAMS__IMAGEALTTEXT |
Run image |
What a screen reader says in its place. |
PRECEPT_REPORTING__TEAMS__MAXFAILURESLISTED |
10 |
How many failed tests the Detailed card names before it gives the remaining count. |
PRECEPT_REPORTING__TEAMS__MAXFAILUREMESSAGELENGTH |
300 |
Longest a failure message may be on the Detailed card. |
PRECEPT_REPORTING__TEAMS__RUNURL |
the agent's build | Where the card's button goes. Left unset, the Azure DevOps build or GitHub Actions run the suite is executing in. |
PRECEPT_REPORTING__TEAMS__RUNURLTITLE |
Open build <number> |
Label on that button; Open the run when no build was detected. |
PRECEPT_REPORTING__TEAMS__LINKTOOTHERREPORTS |
true |
A button per destination this run also reported to — the ReportPortal launch, the Azure DevOps test run. |
PRECEPT_REPORTING__TEAMS__FACTS__<KEY> |
none | An extra row on the card's fact list — a build number, a branch, a browser. |
PRECEPT_REPORTING__TEAMS__TIMEOUTSECONDS |
30 |
How long the post may take before it is given up on. |
Reporting:AzureDevOps#
| Variable | Default | What it does |
|---|---|---|
PRECEPT_REPORTING__AZUREDEVOPS__ENABLED |
true |
Create a test run at all. |
PRECEPT_REPORTING__AZUREDEVOPS__CIONLY |
true |
File results only from a build agent. |
PRECEPT_REPORTING__AZUREDEVOPS__ORGANIZATIONURL |
unset | Required when it runs. For example https://dev.azure.com/acme. |
PRECEPT_REPORTING__AZUREDEVOPS__PROJECT |
unset | Required when it runs. The team project the run belongs to. |
PRECEPT_REPORTING__AZUREDEVOPS__PERSONALACCESSTOKEN |
unset | Credential. Needs Test Management (read & write); Work Items (read) is worth adding but never required. From a pipeline this is normally $(System.AccessToken). |
PRECEPT_REPORTING__AZUREDEVOPS__RUNNAME |
assembly name and environment | Name of the test run. |
PRECEPT_REPORTING__AZUREDEVOPS__RUNBY |
whoever the token is | Who the run is attributed to — an identity GUID, or a unique name for Azure DevOps to resolve. |
PRECEPT_REPORTING__AZUREDEVOPS__BUILDID |
unset | Associates the run with a build, so it appears on that build's Tests tab. Unrelated to RunBy. |
PRECEPT_REPORTING__AZUREDEVOPS__TESTPLANID |
unset | Files the run under a plan, making it a planned run — which accepts a result only when it fills a test point. |
PRECEPT_REPORTING__AZUREDEVOPS__TESTSUITEID |
unset | Narrows a planned run to one suite's points. |
PRECEPT_REPORTING__AZUREDEVOPS__TESTCASETAGPREFIX |
tc: |
Tag prefix naming the Test Case work item: @tc:41207. Empty reads ids from the title only. |
PRECEPT_REPORTING__AZUREDEVOPS__TESTCASETITLEPATTERN |
^\s*(?:\[(?<id>\d+)\]\s*)+ |
Regular expression with a group named id, read from the test's title. Empty reads ids from tags only. |
PRECEPT_REPORTING__AZUREDEVOPS__ONLYMAPPEDTESTS |
false |
Report only tests that name a Test Case work item. A test plan implies it. |
PRECEPT_REPORTING__AZUREDEVOPS__BATCHSIZE |
100 |
Results per call. |
PRECEPT_REPORTING__AZUREDEVOPS__ATTACHARTIFACTS |
true |
Upload each failed test's captured files. |
PRECEPT_REPORTING__AZUREDEVOPS__MAXATTACHMENTBYTES |
8388608 |
Largest artifact uploaded. Azure DevOps itself caps an attachment at 100 MB. |
PRECEPT_REPORTING__AZUREDEVOPS__APIVERSION |
7.1 |
REST API version the calls ask for. |
PRECEPT_REPORTING__AZUREDEVOPS__TIMEOUTSECONDS |
60 |
How long any single call may take. |
Sections of your own#
The rule is not special to Precept's own settings. A class registered with
services.AddPreceptSettings<AuthSettings>() binds from the Auth section — the type's name
without a Precept prefix or a Settings/Options/Configuration/Config suffix — and so reads:
PRECEPT_AUTH__TOKENENDPOINT=https://id.acme.com/token
PRECEPT_AUTH__CLIENTID=test-runner
PRECEPT_AUTH__CLIENTSECRET=… # from the build's secret store, never from precept.json
An explicit section name follows the same shape:
services.AddPreceptSettings<AuthSettings>("Tenants:Primary") reads
PRECEPT_TENANTS__PRIMARY__CLIENTSECRET.
Test data values: a second namespace#
Precept.TestData builds a configuration of its own for the data, and adds the environment to it
under the prefix PRECEPT_TESTDATA__. That is how a password stays out of a data file:
PRECEPT_TESTDATA__USERS__ADMIN__PASSWORD=… # users:admin:password
The path after the prefix is the data path, lowercased by convention and matched
case-insensitively, so this overrides users.admin.password from testdata.json and its overlay.
One caveat, and only for variables. The two namespaces overlap: PRECEPT_TESTDATA__… is seen
by the main configuration as well, under the TestData section — which is where the module's own
settings live. So the four names in TestData mean both things at once, in both
directions. PRECEPT_TESTDATA__DIRECTORY=/data sets the module's directory and injects a data
value at path directory; overriding a root data path called files from a variable would also
rewrite the module's file list.
Data files are unaffected — they are read by the test data store alone, so a JSON key named
directory or files in testdata.json collides with nothing. It is only the environment that
sees both. If a data set has a root key with one of those four names and it has to be overridable
from CI, nest it a level down.
Data files can also read arbitrary variables through a token, which is a different mechanism again — it is resolved where the value is used, not bound to a setting:
{ "users": { "admin": { "note": "{{env:BUILD_BUILDNUMBER}}" } } }
{ "users": { "admin": { "note": "{{env:BUILD_BUILDNUMBER|local}}" } } }
Without a |fallback an unset variable fails the test that reads it, which is the difference
between a suite that runs on a developer's machine and one that only runs on the agent.
Variables Precept reads but does not own#
| Variable | Read for |
|---|---|
PRECEPT_ENVIRONMENT |
The environment. Read directly, ahead of the configuration chain, because the answer decides which overlay that chain loads. |
DOTNET_ENVIRONMENT |
The same, for a suite that already sets it. Consulted only when PRECEPT_ENVIRONMENT says nothing. |
CI |
CI detection — and this one is read for its value: false, 0 and no mean what they say, anything else present counts as CI. |
TF_BUILD, BUILD_BUILDID, GITHUB_ACTIONS, GITLAB_CI, JENKINS_URL, HUDSON_URL, TEAMCITY_VERSION, bamboo_buildKey, BAMBOO_BUILDKEY, CIRCLECI, APPVEYOR, BUILDKITE, DRONE, CODEBUILD_BUILD_ID, TRAVIS |
CI detection. Each is set by one system and by nothing else, so its mere presence is the whole test. BUILD_BUILDID is there for the self-hosted Azure DevOps agent that exports the build variables without TF_BUILD. |
BUILD_BUILDID, BUILD_BUILDNUMBER, SYSTEM_TEAMFOUNDATIONCOLLECTIONURI, SYSTEM_TEAMFOUNDATIONSERVERURI, SYSTEM_TEAMPROJECT |
The ReportPortal reporter builds a link back to the Azure DevOps build from these. Nothing to configure. |
The environment is not the only source for either of those two things. The full resolution order
for the environment is --precept-environment, PRECEPT_ENVIRONMENT, DOTNET_ENVIRONMENT, the
PreceptEnvironment MSBuild property, "Environment" in precept.json, then local; and
IsContinuousIntegration is an ordinary setting whose default is the detection above, so
PRECEPT_ISCONTINUOUSINTEGRATION and an overlay both override it.
What has no variable#
--precept-filter is a command-line option and nothing else. It says what this run selects rather
than how the suite behaves, which is why it is not a setting — and why there is no PRECEPT_FILTER.
That name would be misleading if it existed: Filter is the section holding Filter:Include and
Filter:Exclude, which is the other filter, applied in discovery.
For an IDE with nowhere to type a runner argument, testconfig.json beside the project supplies
command-line options from a file:
{ "commandLineOptions": { "precept-environment": "stage" } }
.runsettings does nothing here at all — it is VSTest-only, and Precept runs on
Microsoft.Testing.Platform.
Working with them#
Set one for a single run:
PRECEPT_MAXPARALLELISM=3 dotnet run --project tests/Acme.Tests -- --list-tests
Every run states the two things most often set wrongly, so a variable that did not take effect is visible in the first line of output:
[Precept] Environment 'stage'. Up to 3 classes in parallel. Filter excluded 5 of 233 tests.
[Precept] There is no 'precept.stag.json' beside the test binary, so the run is using
'precept.json' alone. Check the environment name if that is not what you meant.
The unit is classes or tests depending on ParallelScope, the filter clause appears only when
the configuration filter actually removed something, and the missing-overlay warning is suppressed
for local — which has no overlay by design.
On CI, keep endpoints and project names in precept.json where they can be reviewed, and pass only
the credentials — the four marked Credential above, plus ConnectionStrings — from the build's
secret store. Running a suite on CI is a worked Azure Pipelines example
doing exactly that.