60 lines
1.8 KiB
Markdown
60 lines
1.8 KiB
Markdown
# Testing
|
|
|
|
When testing resources:
|
|
- Test your domain actions through the code interface
|
|
- Use test utilities in `Ash.Test`
|
|
- Test authorization policies work as expected using `Ash.can?`
|
|
- Use `authorize?: false` in tests where authorization is not the focus
|
|
- Write generators using `Ash.Generator`
|
|
- Prefer to use raising versions of functions whenever possible, as opposed to pattern matching
|
|
|
|
## Preventing Deadlocks in Concurrent Tests
|
|
|
|
When running tests concurrently, using fixed values for identity attributes can cause deadlock errors. Multiple tests attempting to create records with the same unique values will conflict.
|
|
|
|
### Use Globally Unique Values
|
|
|
|
Always use globally unique values for identity attributes in tests:
|
|
|
|
```elixir
|
|
# BAD - Can cause deadlocks in concurrent tests
|
|
%{email: "test@example.com", username: "testuser"}
|
|
|
|
# GOOD - Use globally unique values
|
|
%{
|
|
email: "test-#{System.unique_integer([:positive])}@example.com",
|
|
username: "user_#{System.unique_integer([:positive])}",
|
|
slug: "post-#{System.unique_integer([:positive])}"
|
|
}
|
|
```
|
|
|
|
### Creating Reusable Test Generators
|
|
|
|
For better organization, create a generator module:
|
|
|
|
```elixir
|
|
defmodule MyApp.TestGenerators do
|
|
use Ash.Generator
|
|
|
|
def user(opts \\ []) do
|
|
changeset_generator(
|
|
User,
|
|
:create,
|
|
defaults: [
|
|
email: "user-#{System.unique_integer([:positive])}@example.com",
|
|
username: "user_#{System.unique_integer([:positive])}"
|
|
],
|
|
overrides: opts
|
|
)
|
|
end
|
|
end
|
|
|
|
# In your tests
|
|
test "concurrent user creation" do
|
|
users = MyApp.TestGenerators.generate_many(user(), 10)
|
|
# Each user has unique identity attributes
|
|
end
|
|
```
|
|
|
|
This applies to ANY field used in identity constraints, not just primary keys. Using globally unique values prevents frustrating intermittent test failures in CI environments.
|