Angular 1单元测试:如何为appSecurity服务注入Mock userService
Got it, I remember struggling with this exact issue when I first started testing AngularJS services! The key difference from controllers is that services are singletons, so you can't just pass mocks directly when instantiating them like you do with $controller. Instead, you need to tell Angular's injector to use your mock version of userService before it creates the appSecurity service.
Here's a step-by-step solution that works:
1. Set Up the Mock Service Using $provide
In your test's beforeEach block, use Angular's $provide service to replace the real userService with your mock. This ensures that when appSecurity is instantiated, it gets your mock instead of the actual service.
// First, load your app module beforeEach(module('yourAppModuleName')); // Then, configure the injector to use your mock userService beforeEach(module(function($provide) { // Create your mock userService with the properties appSecurity needs const mockUserService = { currentUser: { controlRegisterUsers: [] // We'll populate this in individual tests } }; // Replace the real userService with our mock $provide.value('userService', mockUserService); })); // Now inject the appSecurity service and get a reference to your mock let appSecurity; let userService; beforeEach(inject(function(_appSecurity_, _userService_) { appSecurity = _appSecurity_; userService = _userService_; }));
2. Write Your Test Cases
Now you can easily manipulate the mock userService to test different scenarios for appSecurity methods. For example, testing the routeToErrorPageIfNotFullAccessRoleInCM method:
// Let's assume we need to spy on $state to check if it redirects let $state; beforeEach(inject(function(_$state_) { $state = _$state_; spyOn($state, 'go'); })); it('should NOT redirect to error page when FullAccess role exists', function() { // Arrange: Populate mock user data with a FullAccess role userService.currentUser.controlRegisterUsers = [ { applicationRoles: [{ name: appRolesConstant.FullAccess }] } ]; // Act: Call the method under test appSecurity.routeToErrorPageIfNotFullAccessRoleInCM(); // Assert: Verify no redirect occurred expect($state.go).not.toHaveBeenCalled(); }); it('should redirect to error page when no FullAccess role exists', function() { // Arrange: Populate mock user data without FullAccess role userService.currentUser.controlRegisterUsers = [ { applicationRoles: [{ name: 'ReadOnly' }] } ]; // Act: Call the method under test appSecurity.routeToErrorPageIfNotFullAccessRoleInCM(); // Assert: Verify redirect to error page happened expect($state.go).toHaveBeenCalledWith('yourErrorStateName'); // Replace with actual state });
Key Notes:
- Use
$provide.valueif your mock is a simple object. If you need a mock with methods that return promises, use$provide.factoryinstead. - The underscores around
_appSecurity_and_userService_are a convention in AngularJS testing—they let you inject the service while keeping your variable name clean (Angular automatically strips the underscores).
内容的提问来源于stack exchange,提问作者Sameeksha Kumari

