如何为 CanActivate 函数创建虚拟 ExecutionContext 以进行单元测试?

时间:2021-01-19 06:34:56

标签: typescript nestjs

我有带有 canActivate 功能的 authGuard 服务```

canActivate(context: ExecutionContext): boolean | Promise | Observable

const ctx = GqlExecutionContext.create(context); const { req } = ctx.getContext();

``` 为了使用某些标头值和所有内容测试此函数,我需要传递 ExecutionContext。 那么如何创建虚拟的 ExecutionContext 来测试这个功能呢? 这是 ExecutionContext 的接口。

export interface ExecutionContext extends ArgumentsHost {
    /**
     * Returns the *type* of the controller class which the current handler belongs to.
     */
    getClass<T = any>(): Type<T>;
    /**
     * Returns a reference to the handler (method) that will be invoked next in the
     * request pipeline.
     */
    getHandler(): Function;
}


export interface ArgumentsHost {
    /**
     * Returns the array of arguments being passed to the handler.
     */
    getArgs<T extends Array<any> = any[]>(): T;
    /**
     * Returns a particular argument by index.
     * @param index index of argument to retrieve
     */
    getArgByIndex<T = any>(index: number): T;
    /**
     * Switch context to RPC.
     * @returns interface with methods to retrieve RPC arguments
     */
    switchToRpc(): RpcArgumentsHost;
    /**
     * Switch context to HTTP.
     * @returns interface with methods to retrieve HTTP arguments
     */
    switchToHttp(): HttpArgumentsHost;
    /**
     * Switch context to WebSockets.
     * @returns interface with methods to retrieve WebSockets arguments
     */
    switchToWs(): WsArgumentsHost;
    /**
     * Returns the current execution context type (string)
     */
    getType<TContext extends string = ContextType>(): TContext;

}```

1 个答案:

答案 0 :(得分:1)

我知道有两种直接的方法可以做到这一点。一种是提供具有您需要的基本属性的最小对象。可能是这样的:

fun updateSitesOrderBy(field: String) {
        
        val sortedSites = ArrayList<SiteObject>()
        allSites.let { sortedSites.addAll(it) }

        if (field != orderBySites.value) {
            when (field) {
                DATE_CREATED -> orderBySites.value = DATE_CREATED
                DATE_EDITED -> orderBySites.value = DATE_EDITED
                SITE_TASKS -> orderBySites.value = SITE_TASKS
                SITE_RATING -> orderBySites.value = SITE_RATING
                else -> orderBySites.value = SITE_REFERENCE
            }
        }
                )


        sortedSites.sortBy { it ->
            when (orderBySites.value) {
                DATE_CREATED -> it.dateCreatedTimestamp.toString()
                DATE_EDITED -> it.dateEditedTimestamp.toString()
                SITE_TASKS -> it.siteTask.toString()
                SITE_RATING -> it.siteRating.toString()
                else -> it.siteReference
            }
        }
        
        )

        allSitesMutableLiveData.value = sortedSites
    }

但是,当您使用 const mockContext = { switchToHttp: () => ({ getRequest: () => ({ headers: {}, body: {}, youGetTheIdea: {} }), getResponse: () => similarResMock, }) } 时,您需要将返回值分配给 GqlExecutionContext 具有的 getArgs 方法而不是 ExecutionContext方法。看起来像这样:

switchTo...

对于这两种方法,除非您想模拟每种方法,否则您需要使用 const mockContext = { getType: () => 'graphql', getArgs: () => [{}, {}, gqlContextObject, gqlInfo] }

您的另一个选择是使用模拟对象创建器。如果您使用 as any,您可以使用 jest@golevelup/ts-jest 函数,它可以像这样使用:

createMock

这将返回一个完全有效的 const mockContext = createMock<ExecutionContext>({ getType: () => 'graphql', getArgs: () => [{}, {}, contextMock, infoMock] }) ,您可以在不使用 ExecutionContext 或任何其他类型强制方法的情况下传递它。

I've got an example you can see here