RO EN
Automated testing in React + .NET Core: from unit to integration
Doru Bulubasa
11 June 2025

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;
    }
}

Test with xUnit

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.
    }
}

Test

[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:

  • Moq for mocking

  • AutoFixture for quick data generation


✅ 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"));
        });
    }
}

Test

[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>
  );
}

Test

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.