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": 123n}"
},
"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!