请求协助完成AdminService中getUsers方法的Angular单元测试
getUsers Method in AdminService I'm stuck trying to write a proper unit test for the getUsers method in my AdminService. I've gone through numerous testing resources but haven't found anything that helps me move forward. Here's the relevant code from my service:
admin.service.ts
private bcUrl = 'http://30.30.0.101:8080'; private httpOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/json', 'Authorization': this.cookieService.get('token') }) }; constructor( private http: HttpClient, private cookieService: CookieService, private userService: UserService ) { } getUsers(page, lim): any { return this.http.get(`${this.bcUrl}/api/security/users?page=${page}&size=${lim}`, this.httpOptions) .subscribe( (data: DataInterface) => { this.users = data.content; this.st.totalElements = data.totalElements; this.st.totalPages = data.totalPages; this.dataSource = data.content; }, error => { if (error.status === 404) { alert('Сторінка не знайдена'); } if (error.status === 401) { alert('Немає прав доступу'); } }); }
I've started writing the test code but don't know how to proceed. Here's what I have so far:
Current Test Code
import {async, getTestBed, inject, TestBed} from '@angular/core/testing'; import {CookieService} from 'ngx-cookie-service'; import {AdminService} from './admin.service'; import {HttpClientTestingModule} from '@angular/common/http/testing'; import {UserService} from '@app/core/user/user.service'; import {RequestMethod, ResponseOptions} from '@angular/http'; describe('AdminService', () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule], providers: [AdminService, CookieService, UserService] }); }); it('should be created', inject([AdminService], (service: AdminService) => { expect(service).toBeTruthy(); })); it('should be getUsers', async(() => { const adminService: AdminService = getTestBed().get(AdminService); mockBackend.connections.subscribe(connection => { expect(connection.request.method).toBe(RequestMethod.Delete); connection.mockRespond( new Response(new ResponseOptions())) }); })); });
Could someone help me complete this unit test, or recommend appropriate technical resources to guide me?
Solution
Let's fix and complete your unit test step by step:
1. Fix Imports and Core Setup
First, you're mixing the old @angular/http module with the modern @angular/common/http (used by HttpClientTestingModule). We'll use HttpTestingController instead of mockBackend, and mock CookieService to avoid relying on real browser cookies during tests.
Update your test setup:
import { async, TestBed } from '@angular/core/testing'; import { CookieService } from 'ngx-cookie-service'; import { AdminService } from './admin.service'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { UserService } from '@app/core/user/user.service'; // Import your DataInterface if it's defined in a separate file import { DataInterface } from './path-to-your-data-interface'; describe('AdminService', () => { let adminService: AdminService; let httpTestingController: HttpTestingController; let cookieServiceSpy: jasmine.SpyObj<CookieService>; beforeEach(() => { // Create a spy for CookieService to mock token retrieval const cookieSpy = jasmine.createSpyObj('CookieService', ['get']); cookieSpy.get.and.returnValue('test-auth-token'); TestBed.configureTestingModule({ imports: [HttpClientTestingModule], providers: [ AdminService, { provide: CookieService, useValue: cookieSpy }, UserService // If UserService has its own dependencies, mock it similarly ] }); // Inject services for testing adminService = TestBed.inject(AdminService); httpTestingController = TestBed.inject(HttpTestingController); cookieServiceSpy = TestBed.inject(CookieService) as jasmine.SpyObj<CookieService>; // Mock window.alert to avoid actual browser popups during tests spyOn(window, 'alert'); }); // Clean up after each test to ensure no unmatched HTTP requests afterEach(() => { httpTestingController.verify(); }); it('should be created', () => { expect(adminService).toBeTruthy(); });
2. Test Successful getUsers Call
Now let's test the happy path where the API returns valid user data:
it('should fetch users and update service properties on success', () => { const mockPage = 1; const mockLimit = 10; const mockResponse: DataInterface = { content: [{ id: 1, username: 'test-user-1' }, { id: 2, username: 'test-user-2' }], totalElements: 25, totalPages: 3 }; // Call the method under test adminService.getUsers(mockPage, mockLimit); // Verify the correct HTTP request is made const req = httpTestingController.expectOne( `${adminService['bcUrl']}/api/security/users?page=${mockPage}&size=${mockLimit}` ); expect(req.request.method).toBe('GET'); // Check that headers are correctly set expect(req.request.headers.get('Authorization')).toBe('test-auth-token'); expect(req.request.headers.get('Content-Type')).toBe('application/json'); // Respond with mock data req.flush(mockResponse); // Verify service state is updated correctly expect(adminService['users']).toEqual(mockResponse.content); expect(adminService['st'].totalElements).toBe(mockResponse.totalElements); expect(adminService['st'].totalPages).toBe(mockResponse.totalPages); expect(adminService['dataSource']).toEqual(mockResponse.content); });
3. Test Error Scenarios
Add tests for 404 and 401 error cases to ensure the correct alerts are triggered:
it('should show 404 alert when request fails with 404 status', () => { const mockPage = 1; const mockLimit = 10; adminService.getUsers(mockPage, mockLimit); const req = httpTestingController.expectOne( `${adminService['bcUrl']}/api/security/users?page=${mockPage}&size=${mockLimit}` ); // Respond with 404 error req.flush('Page Not Found', { status: 404, statusText: 'Not Found' }); expect(window.alert).toHaveBeenCalledWith('Сторінка не знайдена'); }); it('should show 401 alert when request fails with 401 status', () => { const mockPage = 1; const mockLimit = 10; adminService.getUsers(mockPage, mockLimit); const req = httpTestingController.expectOne( `${adminService['bcUrl']}/api/security/users?page=${mockPage}&size=${mockLimit}` ); // Respond with 401 error req.flush('Unauthorized', { status: 401, statusText: 'Unauthorized' }); expect(window.alert).toHaveBeenCalledWith('Немає прав доступу'); }); });
Key Notes:
- We use
HttpTestingControllerto intercept and mock HTTP requests (built intoHttpClientTestingModule). - Mocking
CookieServiceensures we don't depend on real browser state during tests. - Spying on
window.alertlets us verify error messages without disrupting test execution. - Accessing private properties (like
bcUrlorusers) via bracket notation is acceptable for testing; for production code, consider adding public getters if you need to access these values elsewhere.
Recommended Learning Resources:
- Angular's official guide on testing HTTP services (core documentation for this scenario)
- Jasmine's SpyObj documentation to learn more about mocking dependencies
- Angular Testing Recipes for service testing best practices
内容的提问来源于stack exchange,提问作者Виктор Кондратьев




