In any serious application – whether it is a blog, an online store, or an enterprise dashboard – automated tests are no longer a "luxury" but a necessity. They provide confidence in the code, ease refactorings, and accelerate the delivery of functionality. In this article, you will learn how to test your React + .NET Core application at all levels: domain, application, API, and frontend.
✅ 1. Testing domain logic (xUnit/NUnit)
We start with the purest area of the code: the domain model (Domain Layer), where the business rules reside.
Example: Aggregate Post
public class Post
{
public Guid Id { get; private set; }
public Slug Slug { get; private set; }
public PostContent Content { get; private set; }
public Post(Slug slug, PostContent content)
{
Id = Guid.NewGuid();
Slug = slug;
Content = content;
}
}
public class PostTests
{
[Fact]
public void Constructor_Should_SetSlugAndContent()
{
// Arrange
var slug = new Slug("first-post");
var content = new PostContent("Hello world!");
// Act
var post = new Post(slug, content);
// Assert
Assert.Equal(slug, post.Slug);
Assert.Equal(content, post.Content);
}
}
✅ Bonus: Use FluentAssertions for expressive asserts.
✅ 2. Testing application services
The Application Layer contains orchestration logic. Here we work with commands, queries, and handlers (if you use MediatR).
Example: CreatePostCommandHandler
public class CreatePostCommandHandler : IRequestHandler<CreatePostCommand, Guid>
{
public Task<Guid> Handle(CreatePostCommand request, CancellationToken cancellationToken)
{
// Create a new post, save in repo, etc.
}
}
[Fact]
public async Task Handle_ShouldReturnPostId_WhenPostIsCreated()
{
// Arrange
var command = new CreatePostCommand("title", "content");
var handler = new CreatePostCommandHandler(/* mocks */);
// Act
var result = await handler.Handle(command, CancellationToken.None);
// Assert
result.Should().NotBeEmpty();
}
✅ Useful tools:
✅ 3. Testing controllers (integration tests)
With WebApplicationFactory we can write tests that start the application as in a real environment, but with an in-memory DB (SQLite or UseInMemoryDatabase()).
Setup
public class CustomWebAppFactory : WebApplicationFactory<Program>
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices(services =>
{
services.RemoveAll(typeof(DbContextOptions<AppDbContext>));
services.AddDbContext<AppDbContext>(options =>
options.UseInMemoryDatabase("TestDb"));
});
}
}
[Fact]
public async Task GetPosts_ShouldReturn200()
{
var client = _factory.CreateClient();
var response = await client.GetAsync("/api/posts");
response.StatusCode.Should().Be(HttpStatusCode.OK);
}
✅ 4. Testing React components (Vitest + React Testing Library)
On the frontend, we use Vitest (vite-native) together with @testing-library/react.
Example: PostList
export function PostList({ posts }: { posts: Post[] }) {
return (
<ul>
{posts.map(p => <li key={p.id}>{p.title}</li>)}
</ul>
);
}
import { render, screen } from "@testing-library/react";
import { PostList } from "./PostList";
test("renders post titles", () => {
render(<PostList posts={[{ id: "1", title: "Hello!" }]} />);
expect(screen.getByText("Hello!")).toBeInTheDocument();
});
✅ Bonus: Use msw (Mock Service Worker) to intercept API requests in tests.
Conclusion
Now you have a complete picture of testing in a React + .NET application:
-
🧠 Unit tests for the domain model
-
🧩 Application tests for handlers and services
-
🌐 Integration tests for the API
-
🎯 UI tests for React
Recommendation: Include tests in CI/CD (GitHub Actions) for automatic checks on every commit.