This content originally appeared on DEV Community and was authored by Yogesh Baghel
To test your notification system backend before implementing the frontend, you can use several approaches. Here are the most effective methods
1. API Testing with Postman/Insomnia
Create a collection to test all endpoints:
{
"info": {
"name": "Notification API Tests",
"description": "Test collection for notification endpoints"
},
"auth": {
"type": "bearer",
"bearer": [
{
"key": "token",
"value": "{{jwt_token}}",
"type": "string"
}
]
},
"item": [
{
"name": "Create Notification",
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"userId\": 1,\n \"title\": \"Test Notification\",\n \"urlt\": \"https://example.com\",\n \"message\": \"This is a test notification\",\n \"sipid\": 123\n}"
},
"url": {
"raw": "{{base_url}}/api/notifications",
"host": ["{{base_url}}"],
"path": ["api", "notifications"]
}
}
},
{
"name": "Get Notifications",
"request": {
"method": "GET",
"url": {
"raw": "{{base_url}}/api/notifications?page=1&pageSize=10",
"host": ["{{base_url}}"],
"path": ["api", "notifications"],
"query": [
{
"key": "page",
"value": "1"
},
{
"key": "pageSize",
"value": "10"
}
]
}
}
},
{
"name": "Get Unread Count",
"request": {
"method": "GET",
"url": {
"raw": "{{base_url}}/api/notifications/unread-count",
"host": ["{{base_url}}"],
"path": ["api", "notifications", "unread-count"]
}
}
},
{
"name": "Mark as Read",
"request": {
"method": "PUT",
"url": {
"raw": "{{base_url}}/api/notifications/1/read",
"host": ["{{base_url}}"],
"path": ["api", "notifications", "1", "read"]
}
}
},
{
"name": "Mark All as Read",
"request": {
"method": "PUT",
"url": {
"raw": "{{base_url}}/api/notifications/mark-all-read",
"host": ["{{base_url}}"],
"path": ["api", "notifications", "mark-all-read"]
}
}
},
{
"name": "Delete Notification",
"request": {
"method": "DELETE",
"url": {
"raw": "{{base_url}}/api/notifications/1",
"host": ["{{base_url}}"],
"path": ["api", "notifications", "1"]
}
}
}
],
"variable": [
{
"key": "base_url",
"value": "https://localhost:5001"
},
{
"key": "jwt_token",
"value": "your_jwt_token_here"
}
]
}
2. Unit Tests
Create comprehensive unit tests for your services:
using ArimartEcommerceAPI.DTOs;
using ArimartEcommerceAPI.Infrastructure.Data.Models;
using ArimartEcommerceAPI.Repositories;
using ArimartEcommerceAPI.Services;
using Microsoft.AspNetCore.SignalR;
using Moq;
using Xunit;
namespace ArimartEcommerceAPI.Tests
{
public class NotificationServiceTests
{
private readonly Mock<INotificationRepository> _mockRepository;
private readonly Mock<IHubContext<NotificationHub>> _mockHubContext;
private readonly NotificationService _service;
public NotificationServiceTests()
{
_mockRepository = new Mock<INotificationRepository>();
_mockHubContext = new Mock<IHubContext<NotificationHub>>();
_service = new NotificationService(_mockRepository.Object, _mockHubContext.Object);
}
[Fact]
public async Task GetNotificationsAsync_ShouldReturnSuccessResponse()
{
// Arrange
var userId = 1L;
var page = 1;
var pageSize = 10;
var expectedResponse = new NotificationListResponse
{
Notifications = new List<NotificationDto>
{
new NotificationDto
{
Id = 1,
UserId = userId,
Title = "Test Notification",
Urlt = "https://example.com",
Message = "Test message",
Acctt = false,
AddedDate = DateTime.UtcNow,
IsActive = true
}
},
TotalCount = 1,
CurrentPage = page,
PageSize = pageSize,
HasMore = false
};
_mockRepository.Setup(r => r.GetNotificationsAsync(userId, page, pageSize))
.ReturnsAsync(expectedResponse);
// Act
var result = await _service.GetNotificationsAsync(userId, page, pageSize);
// Assert
Assert.True(result.Success);
Assert.Equal(expectedResponse, result.Data);
Assert.Equal("Notifications retrieved successfully", result.Message);
}
[Fact]
public async Task CreateNotificationAsync_ShouldCreateAndSendSignalR()
{
// Arrange
var createDto = new CreateNotificationDto
{
UserId = 1L,
Title = "Test Notification",
Urlt = "https://example.com",
Message = "Test message",
Sipid = 123
};
var createdNotification = new TblNotification
{
Id = 1,
UserId = createDto.UserId,
Title = createDto.Title,
Urlt = createDto.Urlt,
Message = createDto.Message,
Acctt = false,
AddedDate = DateTime.UtcNow,
IsActive = true,
Sipid = createDto.Sipid
};
_mockRepository.Setup(r => r.CreateNotificationAsync(createDto))
.ReturnsAsync(createdNotification);
var mockClients = new Mock<IHubCallerClients>();
var mockGroup = new Mock<IClientProxy>();
_mockHubContext.Setup(h => h.Clients).Returns(mockClients.Object);
mockClients.Setup(c => c.Group($"user_{createDto.UserId}")).Returns(mockGroup.Object);
// Act
var result = await _service.CreateNotificationAsync(createDto);
// Assert
Assert.True(result.Success);
Assert.NotNull(result.Data);
Assert.Equal(createdNotification.Id, result.Data.Id);
Assert.Equal("Notification created successfully", result.Message);
// Verify SignalR was called
mockGroup.Verify(g => g.SendCoreAsync("ReceiveNotification",
It.IsAny<object[]>(), default), Times.Once);
}
[Fact]
public async Task MarkAsReadAsync_ShouldUpdateUnreadCount()
{
// Arrange
var notificationId = 1L;
var userId = 1L;
var unreadCount = 5;
_mockRepository.Setup(r => r.MarkAsReadAsync(notificationId, userId))
.ReturnsAsync(true);
_mockRepository.Setup(r => r.GetUnreadCountAsync(userId))
.ReturnsAsync(unreadCount);
var mockClients = new Mock<IHubCallerClients>();
var mockGroup = new Mock<IClientProxy>();
_mockHubContext.Setup(h => h.Clients).Returns(mockClients.Object);
mockClients.Setup(c => c.Group($"user_{userId}")).Returns(mockGroup.Object);
// Act
var result = await _service.MarkAsReadAsync(notificationId, userId);
// Assert
Assert.True(result.Success);
Assert.True(result.Data);
Assert.Equal("Notification marked as read", result.Message);
// Verify SignalR was called with updated count
mockGroup.Verify(g => g.SendCoreAsync("UpdateUnreadCount",
It.Is<object[]>(args => args[0].Equals(unreadCount)), default), Times.Once);
}
[Fact]
public async Task GetUnreadCountAsync_ShouldReturnCount()
{
// Arrange
var userId = 1L;
var expectedCount = 3;
_mockRepository.Setup(r => r.GetUnreadCountAsync(userId))
.ReturnsAsync(expectedCount);
// Act
var result = await _service.GetUnreadCountAsync(userId);
// Assert
Assert.True(result.Success);
Assert.Equal(expectedCount, result.Data);
Assert.Equal("Unread count retrieved successfully", result.Message);
}
[Fact]
public async Task MarkAllAsReadAsync_ShouldResetUnreadCount()
{
// Arrange
var userId = 1L;
_mockRepository.Setup(r => r.MarkAllAsReadAsync(userId))
.ReturnsAsync(true);
var mockClients = new Mock<IHubCallerClients>();
var mockGroup = new Mock<IClientProxy>();
_mockHubContext.Setup(h => h.Clients).Returns(mockClients.Object);
mockClients.Setup(c => c.Group($"user_{userId}")).Returns(mockGroup.Object);
// Act
var result = await _service.MarkAllAsReadAsync(userId);
// Assert
Assert.True(result.Success);
Assert.True(result.Data);
Assert.Equal("All notifications marked as read", result.Message);
// Verify SignalR was called with count 0
mockGroup.Verify(g => g.SendCoreAsync("UpdateUnreadCount",
It.Is<object[]>(args => args[0].Equals(0)), default), Times.Once);
}
[Fact]
public async Task DeleteNotificationAsync_ShouldReturnSuccess()
{
// Arrange
var notificationId = 1L;
var userId = 1L;
_mockRepository.Setup(r => r.DeleteNotificationAsync(notificationId, userId))
.ReturnsAsync(true);
// Act
var result = await _service.DeleteNotificationAsync(notificationId, userId);
// Assert
Assert.True(result.Success);
Assert.True(result.Data);
Assert.Equal("Notification deleted successfully", result.Message);
}
}
}
3. Simple SignalR Test Client
Create a simple console application to test SignalR:
using Microsoft.AspNetCore.SignalR.Client;
using System;
using System.Threading.Tasks;
namespace NotificationTestClient
{
class Program
{
static async Task Main(string[] args)
{
var connection = new HubConnectionBuilder()
.WithUrl("https://localhost:5001/notificationHub", options =>
{
options.AccessTokenProvider = () => Task.FromResult("your_jwt_token_here");
})
.Build();
// Handle incoming notifications
connection.On<object>("ReceiveNotification", (notification) =>
{
Console.WriteLine($"Received notification: {notification}");
});
// Handle unread count updates
connection.On<int>("UpdateUnreadCount", (count) =>
{
Console.WriteLine($"Unread count updated: {count}");
});
try
{
await connection.StartAsync();
Console.WriteLine("Connected to SignalR hub");
// Join user group
await connection.InvokeAsync("JoinUserGroup", "1"); // Replace with actual user ID
Console.WriteLine("Joined user group");
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
finally
{
await connection.DisposeAsync();
}
}
}
}
// Add this to your test project's .csproj file:
/*
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="6.0.0" />
</ItemGroup>
</Project>
*/
4. Integration Tests
Create integration tests to test the entire flow:
using ArimartEcommerceAPI.DTOs;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using System.Net.Http;
using System.Text;
using Xunit;
namespace ArimartEcommerceAPI.IntegrationTests
{
public class NotificationControllerIntegrationTests : IClassFixture<WebApplicationFactory<Program>>
{
private readonly WebApplicationFactory<Program> _factory;
private readonly HttpClient _client;
public NotificationControllerIntegrationTests(WebApplicationFactory<Program> factory)
{
_factory = factory;
_client = _factory.CreateClient();
// Add authorization header for tests
_client.DefaultRequestHeaders.Add("Authorization", "Bearer your_test_jwt_token");
}
[Fact]
public async Task GetNotifications_ShouldReturnOkResponse()
{
// Act
var response = await _client.GetAsync("/api/notifications?page=1&pageSize=10");
// Assert
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<ApiResponse<NotificationListResponse>>(content);
Assert.True(result.Success);
Assert.NotNull(result.Data);
}
[Fact]
public async Task CreateNotification_ShouldReturnCreatedNotification()
{
// Arrange
var createDto = new CreateNotificationDto
{
UserId = 1,
Title = "Integration Test Notification",
Urlt = "https://example.com",
Message = "This is an integration test",
Sipid = 123
};
var json = JsonConvert.SerializeObject(createDto);
var content = new StringContent(json, Encoding.UTF8, "application/json");
// Act
var response = await _client.PostAsync("/api/notifications", content);
// Assert
response.EnsureSuccessStatusCode();
var responseContent = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<ApiResponse<NotificationDto>>(responseContent);
Assert.True(result.Success);
Assert.NotNull(result.Data);
Assert.Equal(createDto.Title, result.Data.Title);
}
[Fact]
public async Task GetUnreadCount_ShouldReturnCount()
{
// Act
var response = await _client.GetAsync("/api/notifications/unread-count");
// Assert
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<ApiResponse<int>>(content);
Assert.True(result.Success);
Assert.True(result.Data >= 0);
}
[Fact]
public async Task MarkAsRead_ShouldReturnSuccess()
{
// First create a notification
var createDto = new CreateNotificationDto
{
UserId = 1,
Title = "Test for Mark as Read",
Urlt = "https://example.com",
Message = "Test message"
};
var json = JsonConvert.SerializeObject(createDto);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var createResponse = await _client.PostAsync("/api/notifications", content);
var createResult = JsonConvert.DeserializeObject<ApiResponse<NotificationDto>>(
await createResponse.Content.ReadAsStringAsync());
// Act - Mark as read
var markReadResponse = await _client.PutAsync($"/api/notifications/{createResult.Data.Id}/read", null);
// Assert
markReadResponse.EnsureSuccessStatusCode();
var markReadContent = await markReadResponse.Content.ReadAsStringAsync();
var markReadResult = JsonConvert.DeserializeObject<ApiResponse<bool>>(markReadContent);
Assert.True(markReadResult.Success);
Assert.True(markReadResult.Data);
}
[Fact]
public async Task MarkAllAsRead_ShouldReturnSuccess()
{
// Act
var response = await _client.PutAsync("/api/notifications/mark-all-read", null);
// Assert
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<ApiResponse<bool>>(content);
Assert.True(result.Success);
Assert.True(result.Data);
}
[Fact]
public async Task DeleteNotification_ShouldReturnSuccess()
{
// First create a notification
var createDto = new CreateNotificationDto
{
UserId = 1,
Title = "Test for Delete",
Urlt = "https://example.com",
Message = "Test message"
};
var json = JsonConvert.SerializeObject(createDto);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var createResponse = await _client.PostAsync("/api/notifications", content);
var createResult = JsonConvert.DeserializeObject<ApiResponse<NotificationDto>>(
await createResponse.Content.ReadAsStringAsync());
// Act - Delete notification
var deleteResponse = await _client.DeleteAsync($"/api/notifications/{createResult.Data.Id}");
// Assert
deleteResponse.EnsureSuccessStatusCode();
var deleteContent = await deleteResponse.Content.ReadAsStringAsync();
var deleteResult = JsonConvert.DeserializeObject<ApiResponse<bool>>(deleteContent);
Assert.True(deleteResult.Success);
Assert.True(deleteResult.Data);
}
}
}
5. Manual Testing Steps
Here’s a step-by-step manual testing approach:
Step 1: Test Authentication
Ensure your JWT authentication is working
Get a valid JWT token for testing
Step 2: Test API Endpoints
Create notifications – Use POST /api/notifications
Get notifications – Use GET /api/notifications
Get unread count – Use GET /api/notifications/unread-count
Mark as read – Use PUT /api/notifications/{id}/read
Mark all as read – Use PUT /api/notifications/mark-all-read
Delete notification – Use DELETE /api/notifications/{id}
Step 3: Test SignalR Hub
Use the SignalR test client above
Create notifications and verify real-time updates
Test mark as read and verify unread count updates
Step 4: Test Database
Check if notifications are being stored correctly
Verify soft deletion (IsDeleted flag)
Check if read status is updating properly
6. Quick Test Script
You can also create a simple test script to automate basic testing:
# Notification API Test Script
$baseUrl = "https://localhost:5001"
$token = "your_jwt_token_here"
$headers = @{
"Authorization" = "Bearer $token"
"Content-Type" = "application/json"
}
# Test 1: Create Notification
Write-Host "Testing Create Notification..." -ForegroundColor Green
$createNotificationBody = @{
userId = 1
title = "Test Notification"
urlt = "https://example.com"
message = "This is a test notification"
sipid = 123
} | ConvertTo-Json
try {
$createResponse = Invoke-RestMethod -Uri "$baseUrl/api/notifications" -Method Post -Body $createNotificationBody -Headers $headers
Write-Host "Create Notification: SUCCESS" -ForegroundColor Green
Write-Host "Created notification ID: $($createResponse.data.id)" -ForegroundColor Yellow
$notificationId = $createResponse.data.id
} catch {
Write-Host "Create Notification: FAILED - $($_.Exception.Message)" -ForegroundColor Red
}
# Test 2: Get Notifications
Write-Host "`nTesting Get Notifications..." -ForegroundColor Green
try {
$getResponse = Invoke-RestMethod -Uri "$baseUrl/api/notifications?page=1&pageSize=10" -Method Get -Headers $headers
Write-Host "Get Notifications: SUCCESS" -ForegroundColor Green
Write-Host "Total notifications: $($getResponse.data.totalCount)" -ForegroundColor Yellow
} catch {
Write-Host "Get Notifications: FAILED - $($_.Exception.Message)" -ForegroundColor Red
}
# Test 3: Get Unread Count
Write-Host "`nTesting Get Unread Count..." -ForegroundColor Green
try {
$countResponse = Invoke-RestMethod -Uri "$baseUrl/api/notifications/unread-count" -Method Get -Headers $headers
Write-Host "Get Unread Count: SUCCESS" -ForegroundColor Green
Write-Host "Unread count: $($countResponse.data)" -ForegroundColor Yellow
} catch {
Write-Host "Get Unread Count: FAILED - $($_.Exception.Message)" -ForegroundColor Red
}
# Test 4: Mark as Read
if ($notificationId) {
Write-Host "`nTesting Mark as Read..." -ForegroundColor Green
try {
$markReadResponse = Invoke-RestMethod -Uri "$baseUrl/api/notifications/$notificationId/read" -Method Put -Headers $headers
Write-Host "Mark as Read: SUCCESS" -ForegroundColor Green
} catch {
Write-Host "Mark as Read: FAILED - $($_.Exception.Message)" -ForegroundColor Red
}
}
# Test 5: Mark All as Read
Write-Host "`nTesting Mark All as Read..." -ForegroundColor Green
try {
$markAllReadResponse = Invoke-RestMethod -Uri "$baseUrl/api/notifications/mark-all-read" -Method Put -Headers $headers
Write-Host "Mark All as Read: SUCCESS" -ForegroundColor Green
} catch {
Write-Host "Mark All as Read: FAILED - $($_.Exception.Message)" -ForegroundColor Red
}
# Test 6: Delete Notification
if ($notificationId) {
Write-Host "`nTesting Delete Notification..." -ForegroundColor Green
try {
$deleteResponse = Invoke-RestMethod -Uri "$baseUrl/api/notifications/$notificationId" -Method Delete -Headers $headers
Write-Host "Delete Notification: SUCCESS" -ForegroundColor Green
} catch {
Write-Host "Delete Notification: FAILED - $($_.Exception.Message)" -ForegroundColor Red
}
}
Write-Host "`nAll tests completed!" -ForegroundColor Blue
Testing Order:
- Start with Unit Tests – Test individual components in isolation
- Run Integration Tests – Test the entire API flow
- Use Postman/Manual Testing – Test real HTTP requests
- Test SignalR – Use the console client to verify real-time functionality
- Run the PowerShell script – For quick automated testing This comprehensive testing approach will ensure your notification system is working correctly before you build the frontend!
This content originally appeared on DEV Community and was authored by Yogesh Baghel