Osy#the first language built for agents
Agents firstAgentic appsWorkflowsDurable Execution — built inSecurityTestingThe editorThe UI modelOne program

Reference / Testing

Outbound calls in a test

A `[Test]` reaches the network for real — `Http.*` and a typed `client { }` operation both run inside a test, against the live endpoint. So a test can prove the one thing a green suite otherwise cannot: that the call your app depends on actually works.

preview2 examples compiled by CItestinghttpintegration

Summary#

A [Test] runs with the same capabilities the app has. Http.Get(...) inside a test makes the request, and a typed client { } operation does too. Nothing is stubbed by default, so a test that calls your fetch function and reads back what it stored is telling you about the real endpoint.

That matters more than it sounds, because it is the one thing the rest of the suite cannot tell you. Every other check — compile, lint, render, assert — passes just as happily when the URL is dead, the API key is missing or the response shape changed. A green suite is not evidence that the endpoint works unless a test called it.

Description#

An app that reads a value from outside has two halves, and they fail differently:

halfwhat breakswhat catches it
the CALLa dead URL, a moved path, a missing key, a rate limitonly a test that makes the call
the PARSEa changed response shape, a field that is now nesteda test with a canned body, or the real one

The second half can be tested without the network: call the function that CONSUMES a response, handing it a body you wrote. The first half cannot — and it is the half that fails silently in production, because a fetch that never arrives usually leaves the app showing whatever it had before.

A non-2xx is a normal return, not an exception. response.IsSuccess goes false and the body holds whatever the server sent; nothing throws, so a try/catch around the call will not see it. Assert on IsSuccess, and remember that some APIs answer HTTP 200 carrying an error document — a status check alone will not catch those, but reading back what your app STORED will.

Every outbound call is logged whatever happens — a 2xx at Information, anything else at Warning, with the method, the URL (query redacted), the status and the duration. osy logs is where a failing call explains itself.

Examples#

Prove the whole path — the call, the parse and the storage — by running your own fetch and reading back the row:

using Osyrin.Http;

entity ExchangeRate {
  [Required] decimal GbpToEur;
  security { allow read, create when IsAnonymous; }
}

void RefreshExchangeRate() {
  var r = Http.Get("https://open.er-api.com/v6/latest/GBP");
  new ExchangeRate { GbpToEur = 1.17m };      // …parsed from `r.Body` in a real app
  UnitOfWork.Commit();
}

[Test]
void the_rate_fetch_stores_a_real_rate() {
  RefreshExchangeRate();                       // the app's own function: it calls out, parses, and writes
  var rate = ExchangeRate.FirstOrDefault();
  Assert.NotNull(rate);
  Assert.True(rate.GbpToEur > 0m, "a stored rate must be a real number");
}

Ask the endpoint what it actually answers, when you are not sure it is alive or keyless:

using Osyrin.Http;

[Test]
void the_endpoint_is_reachable_and_keyless() {
  var r = Http.Get("https://open.er-api.com/v6/latest/GBP");
  Assert.True(r.IsSuccess, "expected a 2xx");
  Assert.Contains("\"rates\"", r.Body);        // a 200 carrying an error document would fail HERE, not above
}

A test that calls out depends on somebody else's uptime. That is the right trade for the one or two tests that exist to prove the integration, and the wrong one for a suite of thirty. Keep the network in the tests whose subject IS the network, and test everything downstream of the response against a body you supply.

See also#

Related

[Test] / [TestFixture]

A test is an ordinary function marked [Test]. It runs against a throwaway clone of the app, so it may create rows and…

Testing (real app, real data, real rules)

A test in Osy# is not a unit test with the world mocked out. It is your app, running against its own throwaway…

Http.*

Make an outbound HTTP call to a URL you build at runtime — a webhook, a third-party API, a discovered endpoint…