使用 sinon 在 vue 动作中模拟 class 进行单元测试
Mock class in vue action with sinon for unit testing
我希望能够断言我的 'SIGN_IN' 操作是否按预期工作。
我的操作看起来像这样(不是最干净的实现,但这是我现在必须使用的):
// actions.js
import {
SIGN_IN, SIGN_OUT, SET_AUTH_TOKEN, CLEAR_AUTH_TOKEN, USER_AUTHORISED,
} from '@/store/types';
import AuthService from '../../../authService';
export default {
async [SIGN_IN]({ commit, rootState }) {
const authService = new AuthService(rootState.clientSettings);
let response;
try {
response = await authService.getToken();
} catch (e) {
console.log('User not authorised to use application.');
}
if (response) {
commit(SET_AUTH_TOKEN, response);
} else {
commit(USER_AUTHORISED, false);
}
},
...
};
authService.getToken();
是我想要模拟的响应。
我希望这能够解决我测试中的模拟响应。
AuthService 的 class 如下所示:
// authService.js
import { PublicClientApplication } from '@azure/msal-browser';
class AuthService {
constructor(clientSettings) {
this.config = {
auth: {
clientId: clientSettings.clientId,
authority: `https://login.microsoftonline.com/${clientSettings.tenantId}`,
},
cache: {
cacheLocation: 'sessionStorage',
storeAuthStateInCookie: false,
},
};
this.scopes = [
clientSettings.appScope,
];
this.msal = new PublicClientApplication(this.config);
this.clientSettings = clientSettings;
}
...
async getToken() {
const { scopes } = this;
try {
const response = await this.msal.acquireTokenSilent({ scopes });
return response;
} catch (err) {
const response = await this.msal.acquireTokenPopup({ scopes });
return response;
}
}
...
}
export default AuthService;
这是我在测试中尝试的:
// actions.spec.js
import sinon, { mock } from 'sinon';
import actions from '@/store/modules/auth/actions';
import { SIGN_IN, SIGN_OUT } from '@/store/types';
import { PublicClientApplication } from '@azure/msal-browser';
import AuthService from '../../../../../src/authService';
import templateRootState from '../../../../helpers/rootState.json';
describe('Auth', () => {
describe('Actions', () => {
let state;
beforeEach(() => {
state = JSON.parse(JSON.stringify(templateRootState));
});
afterEach(() => {
sinon.reset();
});
describe('SIGN_IN', () => {
it.only('returns a token from the AuthService & sets it in the store', async () => {
const commit = sinon.spy();
const mockResponse = {
token: 'bobbins'
};
sinon.stub(AuthService, 'getToken').resolves(mockResponse);
const requestParams = { commit, rootState: state };
await actions[SIGN_IN](requestParams);
expect(commit.calledOnce).toEqual(true);
expect(commit.args.length).toEqual(1);
expect(commit.args[0][0]).toEqual('SET_AUTH_TOKEN');
expect(commit.args[0][1]).toEqual(mockResponse);
});
});
});
});
调试时,我无法将 getToken
设为存根响应。它仍然调用在我的操作中创建的实际 userService
class 实例:new AuthService(rootState.clientSettings);
.
希望您能看到我试图通过测试实现的目标。我只想断言 SET_AUTH_TOKEN
已触发,仅此而已。我怎样才能完全删除这个 AuthService
class 以便我的操作使用那个?我真的不想将 AuthService
的实例传递给操作本身,一定有更简洁的方法吗?
你需要的是存根原型方法。
sinon.stub(AuthService.prototype, 'getToken').resolves(mockResponse);
我希望能够断言我的 'SIGN_IN' 操作是否按预期工作。
我的操作看起来像这样(不是最干净的实现,但这是我现在必须使用的):
// actions.js
import {
SIGN_IN, SIGN_OUT, SET_AUTH_TOKEN, CLEAR_AUTH_TOKEN, USER_AUTHORISED,
} from '@/store/types';
import AuthService from '../../../authService';
export default {
async [SIGN_IN]({ commit, rootState }) {
const authService = new AuthService(rootState.clientSettings);
let response;
try {
response = await authService.getToken();
} catch (e) {
console.log('User not authorised to use application.');
}
if (response) {
commit(SET_AUTH_TOKEN, response);
} else {
commit(USER_AUTHORISED, false);
}
},
...
};
authService.getToken();
是我想要模拟的响应。
我希望这能够解决我测试中的模拟响应。
AuthService 的 class 如下所示:
// authService.js
import { PublicClientApplication } from '@azure/msal-browser';
class AuthService {
constructor(clientSettings) {
this.config = {
auth: {
clientId: clientSettings.clientId,
authority: `https://login.microsoftonline.com/${clientSettings.tenantId}`,
},
cache: {
cacheLocation: 'sessionStorage',
storeAuthStateInCookie: false,
},
};
this.scopes = [
clientSettings.appScope,
];
this.msal = new PublicClientApplication(this.config);
this.clientSettings = clientSettings;
}
...
async getToken() {
const { scopes } = this;
try {
const response = await this.msal.acquireTokenSilent({ scopes });
return response;
} catch (err) {
const response = await this.msal.acquireTokenPopup({ scopes });
return response;
}
}
...
}
export default AuthService;
这是我在测试中尝试的:
// actions.spec.js
import sinon, { mock } from 'sinon';
import actions from '@/store/modules/auth/actions';
import { SIGN_IN, SIGN_OUT } from '@/store/types';
import { PublicClientApplication } from '@azure/msal-browser';
import AuthService from '../../../../../src/authService';
import templateRootState from '../../../../helpers/rootState.json';
describe('Auth', () => {
describe('Actions', () => {
let state;
beforeEach(() => {
state = JSON.parse(JSON.stringify(templateRootState));
});
afterEach(() => {
sinon.reset();
});
describe('SIGN_IN', () => {
it.only('returns a token from the AuthService & sets it in the store', async () => {
const commit = sinon.spy();
const mockResponse = {
token: 'bobbins'
};
sinon.stub(AuthService, 'getToken').resolves(mockResponse);
const requestParams = { commit, rootState: state };
await actions[SIGN_IN](requestParams);
expect(commit.calledOnce).toEqual(true);
expect(commit.args.length).toEqual(1);
expect(commit.args[0][0]).toEqual('SET_AUTH_TOKEN');
expect(commit.args[0][1]).toEqual(mockResponse);
});
});
});
});
调试时,我无法将 getToken
设为存根响应。它仍然调用在我的操作中创建的实际 userService
class 实例:new AuthService(rootState.clientSettings);
.
希望您能看到我试图通过测试实现的目标。我只想断言 SET_AUTH_TOKEN
已触发,仅此而已。我怎样才能完全删除这个 AuthService
class 以便我的操作使用那个?我真的不想将 AuthService
的实例传递给操作本身,一定有更简洁的方法吗?
你需要的是存根原型方法。
sinon.stub(AuthService.prototype, 'getToken').resolves(mockResponse);