mit einem Klick
write-test
// Write tests for the Stream Video Unity SDK. Use when creating, modifying, or reviewing test files. Covers assembly structure, naming conventions, base classes, async patterns, and all project-specific rules.
// Write tests for the Stream Video Unity SDK. Use when creating, modifying, or reviewing test files. Covers assembly structure, naming conventions, base classes, async patterns, and all project-specific rules.
| name | write-test |
| description | Write tests for the Stream Video Unity SDK. Use when creating, modifying, or reviewing test files. Covers assembly structure, naming conventions, base classes, async patterns, and all project-specific rules. |
Guidelines and conventions for writing tests in the Stream Video Unity SDK.
Tests live under Tests/ in three assemblies:
| Assembly | Folder | Purpose | Inherits TestsBase? |
|---|---|---|---|
StreamVideo.Tests.Editor | Tests/Editor/ | Pure-logic editor tests — no networking or live client | No (unless the test needs a connection, e.g. StreamClientTests) |
StreamVideo.Tests.Runtime | Tests/Runtime/ | Integration tests — require a live Stream Video client | Yes, always |
StreamVideo.Tests.Shared | Tests/Shared/ | Shared base classes, utilities, test client infra | N/A (not tests themselves) |
Never create new .asmdef files. Place your file in the correct existing folder.
Every test .cs file must be wrapped in:
#if STREAM_TESTS_ENABLED
// ... entire file contents ...
#endif
This is a master kill-switch that prevents test code from compiling in production builds.
StreamVideo.Tests.EditorStreamVideo.Tests.RuntimeStreamVideo.Tests.Sharedinternal (optionally sealed for editor tests).{SubjectUnderTest}Tests — e.g. SessionIDTests, CallsTests.<summary> comment on the class referencing the class under test via <see cref="..."/>.All tests (editor and runtime) use the same pattern: When_<condition>_expect_<outcome> with underscores:
When_new_instance_expect_empty
When_regenerate_expect_version_increments
When_clear_expect_version_unchanged
When_two_clients_join_same_call_expect_no_errors
When_setting_call_custom_data_expect_custom_data_set
When_participant_pinned_expect_pinned_participants_changed_event_fired
For runtime tests that use the async bridge, the private async companion uses the same name with an _Async suffix:
When_two_clients_join_same_call_expect_no_errors_Async
{Feature}Tests.cs in Tests/Editor/.TestsBase.[Test] attribute for synchronous tests.[SetUp] for per-test initialization.Assert.That(...)) with descriptive failure messages.#if STREAM_TESTS_ENABLED
using NUnit.Framework;
using StreamVideo.Core.SomeNamespace;
namespace StreamVideo.Tests.Editor
{
/// <summary>
/// Tests for <see cref="MyFeature"/>.
/// </summary>
internal sealed class MyFeatureTests
{
[SetUp]
public void SetUp()
{
_myFeature = new MyFeature();
}
[Test]
public void When_default_state_expect_some_property_has_expected_value()
{
Assert.That(_myFeature.SomeProperty, Is.EqualTo(expectedValue),
"Descriptive failure message explaining what went wrong.");
}
private MyFeature _myFeature;
}
}
#endif
{Feature}Tests.cs in Tests/Runtime/.TestsBase.[UnityTest] attribute (returns IEnumerator).ConnectAndExecute(...) which handles client provisioning, connection, and retry-on-rate-limit.async Task method with the _Async suffix.ConnectAndExecute overload:
ConnectAndExecute(SingleClientTestHandler) — one ITestClientConnectAndExecute(TwoClientsTestHandler) — two ITestClient paramsConnectAndExecute(Func<Task>) — no client params (connection still happens)#if STREAM_TESTS_ENABLED
using System.Collections;
using System.Threading.Tasks;
using NUnit.Framework;
using StreamVideo.Tests.Shared;
using UnityEngine.TestTools;
namespace StreamVideo.Tests.Runtime
{
/// <summary>
/// Tests for <see cref="SomeFeature"/>.
/// </summary>
internal class SomeFeatureTests : TestsBase
{
[UnityTest]
public IEnumerator When_doing_X_expect_Y()
=> ConnectAndExecute(When_doing_X_expect_Y_Async);
private async Task When_doing_X_expect_Y_Async(ITestClient client)
{
var call = await client.JoinRandomCallAsync();
// ... test logic ...
await WaitForConditionAsync(() => /* condition to poll */);
Assert.AreEqual(expected, actual);
}
}
}
#endif
Unity's [UnityTest] requires IEnumerator, but test logic is async Task. The bridge works like this:
[UnityTest] public IEnumerator MethodName()
=> ConnectAndExecute(MethodName_Async);
ConnectAndExecute internally calls RunAsIEnumerator() (from TestUtils) which polls task.IsCompleted each frame and rethrows faults. You never need to call RunAsIEnumerator() directly in a runtime test that uses ConnectAndExecute.
For editor tests that are async but don't need a client, use the Execute(...) helper:
[UnityTest]
public IEnumerator My_async_editor_test()
=> Execute(My_async_editor_test_Async);
Or call RunAsIEnumerator() directly on the task:
[UnityTest]
public IEnumerator My_async_editor_test()
=> My_async_editor_test_Async().RunAsIEnumerator();
| Utility | What it does |
|---|---|
TestsBase | Base class for runtime tests. Manages client lifecycle, teardown, retry logic. |
ITestClient / TestClient | Wraps IStreamVideoClient with test helpers like JoinRandomCallAsync(). |
StreamTestClientProvider | Singleton that pools and reuses IStreamVideoClient instances across fixtures. |
WaitForConditionAsync(condition, timeoutMs) | Polls a Func<bool> until true or timeout. Use instead of Task.Delay. |
DisposableAssetsProvider | Tracks and disposes Unity assets (e.g. WebCamTexture) created during tests. |
TestUtils.RunAsIEnumerator() | Extension method bridging Task → IEnumerator for Unity test runner. |
TestUtils.TryGetFirstWorkingCameraDeviceAsync() | Finds a working camera device for video tests. |
If a test requires a camera device, add the conditional ignore attribute:
[UnityTest, ConditionalIgnore(IgnoreConditionNoCameraKey, IgnoreConditionNoCameraReason)]
public IEnumerator When_client_joins_call_with_video_expect_receiving_video_track()
=> ConnectAndExecute(When_client_joins_call_with_video_expect_receiving_video_track_Async,
ignoreFailingMessages: true);
These constants are defined in TestsBase.
#if STREAM_TESTS_ENABLED / #endif..asmdef — use the existing Tests/Editor/ or Tests/Runtime/ folder.TestsBase for runtime tests; don't for pure-logic editor tests.When_<condition>_expect_<outcome> for all tests (editor and runtime).[UnityTest] → IEnumerator → ConnectAndExecute → private async Task with _Async suffix.TestsBase and StreamTestClientProvider handle it.WaitForConditionAsync instead of Task.Delay for polling asynchronous state.DisposableAssetsProvider.internal — tests are not public API.<summary> XML doc comments on the class with <see cref="..."/> to the subject under test.Tests/Shared/ — never duplicate utilities across Editor and Runtime.