# [runas(Name)] test attribute and principal selectors

> A test runs deny-all as an anonymous principal, so to read or write real data it must act AS a seeded `[Principal]`. Declare a named selector with `principal Name => <query>;`, then put `[runas(Name)]` on a `[Test]` to run its whole body as that principal. The `runas(){}` block form stays for the rarer case of switching principals mid-test. `[runas]` binds to a fixture-seeded row and never creates one.

<!-- id: testing-runas-attribute · area: testing · stability: preview · html: https://osysharp.com/reference/testing/runas-attribute/ -->

## Summary        {#summary}
An app is **deny-all by default**, and a `[Test]` runs in a secured context as an **initially-anonymous** principal.
So any test that reads or writes real data must act **as** some seeded `[Principal]` row. Two pieces make that
declarative:

- **`principal Name => <selector>;`** — a top-level declaration that names a selector resolving, at runtime, to a
  single `[Principal]` row (e.g. `principal Alice => User.Single(u => u.Name == "Alice");`). It mirrors a
  `policy Name => …;`, but the body is a single-entity query, not a boolean.
- **`[runas(Name)]`** — an attribute on a `[Test]` that runs the **whole body** as that principal.

The `runas(<expr>) { … }` **block** form is still there for the case it is uniquely good at: **two principals in one
test** (Alice creates a row; then as Bob, assert he cannot see it). Attribute = whole test; block = a sub-region;
the inner block wins for its span.

## Signature      {#signature}
```osy syntax
principal <Name> => <single-entity selector>;   // names a seeded [Principal] row

[Test(<Fixture>)]
[runas(<Name>)]                                  // the whole body runs as <Name>
void <TestName>() { … }
```

## Description    {#description}
`[runas(Name)]` **binds, never creates.** The named selector must resolve to a row the fixture already seeded; a
selector that matches nothing fails the test loudly (it is `User.Single(…)`, not a silent fallback). Naming a
principal that was never declared is a compile error, as is putting `[runas]` on a function that is not a `[Test]`.
This is deliberate — if `[runas]` could conjure a principal, a denial test would be fake, quietly passing against a
principal that production would never grant.

Running as a principal rebinds **more than the row**: the effective **role** list is resolved for that principal
(so a role-gated `allow read when …` activates only for a principal actually granted the role), and role-dependent
row filters re-evaluate against the acting user. Data staged during the test **settles as that principal** at the end
of the run, so an owner-scoped write commits under the owner with no extra ceremony.

A declared **principal name is also usable as a value**: writing `Alice` where a value is expected resolves to that
same seeded row (its selector), so `new Doc { Owner = Alice }` reads naturally — no `var alice = User.Single(…)`
re-query. An ordinary local, parameter, or entity of the same name always shadows it (the principal name is a
last-resort resolution, never an override).

Use the attribute for the common case — "this whole test runs as one principal" — and reach for the `runas(){}`
block only when a single test genuinely needs to change principals partway through, or must assert **outside** the
run-as region (for example, to observe what committed after the block settled).

A `principal` declaration is authored in a test context alongside the `[TestFixture]` that seeds its row; the fixture
seeds unsecured (so it can create freely), and the selector gives that row a compile-time name the attribute carries.

## Examples       {#examples}

A single-principal read test — the whole body runs as Alice, who sees only her own owner-scoped rows:

```osy title="the model — locked, the way a real app is" test app=runas-example
[Principal]
entity User {
  [Required, MaxLength(60)] string Name;
  security { allow read where Id == user.Id; }   // you can read yourself. Nobody enumerates the user table.
}

entity Doc {
  [Required] User Owner;
  [MaxLength(200)] string Title;
  security {
    allow create when IsAuthenticated;
    allow read where Owner == user;
  }
}
```

```osy title="whole-body run-as" run app=runas-example
principal Alice => User.Single(u => u.Name == "Alice");
principal Bob   => User.Single(u => u.Name == "Bob");

[TestFixture]
void Seed() {
  var alice = new User { Name = "Alice" };
  var bob = new User { Name = "Bob" };
  var d = new Doc { Owner = alice, Title = "alice-doc" };
}

[Test(Seed)]
[runas(Alice)]
void Alice_sees_only_her_own_rows() {
  Assert.NotNull(Doc.FirstOrDefault(d => d.Title == "alice-doc"));
}

// Two principals in one test — the case the attribute alone cannot express. `[runas(Alice)]` is the body's
// default; the inner `runas(Bob) { }` block wins for its span.
[Test(Seed)]
[runas(Alice)]
void Alice_creates_Bob_cannot_see() {
  var secret = new Doc { Owner = Alice, Title = "secret" };   // `Alice` as a value — the seeded row
  runas(Bob) {
    Assert.Null(Doc.FirstOrDefault(d => d.Title == "secret"));
  }
}
```

Note that the `User` table above is **locked** — nothing may enumerate it, which is how you would really write it. The
selector still finds Alice, because binding *who a test acts as* is scaffolding, not an app data read: it resolves the
same way the fixture seeds, past the app's own rules. **You never have to loosen the user table to test your
security.**

The second test is a real proof rather than an illustration: the row is created by one user and genuinely **not
selected** for the other. The rule is inside the query, so there is nothing for Bob to be "hidden" from.

## See also       {#see-also}
- [Testing (real app, real data, real rules)](https://osysharp.com/reference/testing/index/) — the testing guide: who a test acts as, and how you prove a rule
- [secure by default (deny-all)](https://osysharp.com/reference/security/secure-by-default/) — why a test starts deny-all and anonymous
- [principal predicates (IsAuthenticated / IsAnonymous) and open reads](https://osysharp.com/reference/security/principal-predicates/) — the `[Principal]` marker and who a request is
- [Running tests](https://osysharp.com/reference/testing/running-tests/) — authoring and running `[Test]` / `[TestFixture]`
