Sinon: Não é possível criarStubInstance na classe com membros privados

Criado em 4 jan. 2019  ·  3Comentários  ·  Fonte: sinonjs/sinon

Descreva o erro
se eu sinon.createStubInstance(X) onde X é uma classe com pelo menos um membro privado, recebo erros como:

Argumento do tipo 'SinonStubbedInstance' não é atribuível ao parâmetro do tipo 'Foo'.
A propriedade '_private' está ausente no tipo 'SinonStubbedInstance' mas necessário no tipo 'Foo'.

describe('SinonTest', () => {
  class Foo {
    public talk() {
      return 'hi';
    }
    private _private() {
      return null;
    }
  }

  function printSpeech(foo: Foo) {
    console.log(foo.talk());
  }
  it('should allow you to pass a stub as a the original', () => {
    const mockFoo = sinon.createStubInstance(Foo);

    printSpeech(mockFoo);
  });
});

Reproduzir
Etapas para reproduzir o comportamento:

  1. Monte um projeto com mocha e sinon.
  2. Criar um arquivo de especificação de teste de unidade
  3. Cole o snippet de código acima e adicione as importações necessárias
  4. Veja o erro online com printSpeech(mockFoo)

Comportamento esperado
Eu esperaria que isso funcionasse sem erros. Não me importo com _private(), nem pretendo testar diretamente seu comportamento, mas isso não deve resultar em um erro de tempo de compilação. Jasmine suporta este caso com jasmine.createSpyObj , embora a implementação de jasmine tenha outras falhas.

Contexto (por favor, preencha as seguintes informações):

  • Versão da biblioteca: sinon: 7.2.2, @types/sinon: 7.0.3
  • Ambiente: WSL Ubuntu 16.04, Nó 10

  • Outras bibliotecas que você está usando: Mocha 5.2.0

edit: aqui está um stackblitz https://stackblitz.com/edit/typescript-nfbgno?file=index.ts

Ele reclama do process.stdout porque está sendo executado no navegador, mas isso não é importante, pois o problema real é o tempo de compilação

Comentários muito úteis

Esta não é uma solução definitiva, mas consegui corrigir esse problema com a seguinte função:

import { createStubInstance, StubbableType, SinonStubbedInstance, SinonStubbedMember } from 'sinon';

export type StubbedClass<T> = SinonStubbedInstance<T> & T;

export function createSinonStubInstance<T>(
  constructor: StubbableType<T>,
  overrides?: { [K in keyof T]?: SinonStubbedMember<T[K]> },
): StubbedClass<T> {
  const stub = createStubInstance<T>(constructor, overrides);
  return stub as unknown as StubbedClass<T>;
}

Obviamente, isso não implementa nenhum método privado e, como tal, você não pode (e não deve por design) chamá-los. Ao usar esta função wrapper, você obtém a conclusão de código para todas as funções/membros públicos em sua classe, bem como as funções auxiliares de stub do sinon e StubbedClassé um tipo válido para ser usado como T em seus testes.

Todos 3 comentários

Este é um problema datilografado. Não vamos gastar tempo analisando isso, pois não suportamos o Typescript explicitamente. Que o Typescript de alguma forma tenha suporte para membros privados é uma propriedade de seu sistema de tipos e pode ser implementado de várias maneiras. Quando usei o Typescript, muitas vezes resolvi esses problemas indo ao playground do Typescript e inspecionando a saída para entender o que ela fazia. Isso é o que você precisa fazer também.

Esta não é uma solução definitiva, mas consegui corrigir esse problema com a seguinte função:

import { createStubInstance, StubbableType, SinonStubbedInstance, SinonStubbedMember } from 'sinon';

export type StubbedClass<T> = SinonStubbedInstance<T> & T;

export function createSinonStubInstance<T>(
  constructor: StubbableType<T>,
  overrides?: { [K in keyof T]?: SinonStubbedMember<T[K]> },
): StubbedClass<T> {
  const stub = createStubInstance<T>(constructor, overrides);
  return stub as unknown as StubbedClass<T>;
}

Obviamente, isso não implementa nenhum método privado e, como tal, você não pode (e não deve por design) chamá-los. Ao usar esta função wrapper, você obtém a conclusão de código para todas as funções/membros públicos em sua classe, bem como as funções auxiliares de stub do sinon e StubbedClassé um tipo válido para ser usado como T em seus testes.

A resposta @pauloavelar ainda é a solução recomendada?

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

OscarF picture OscarF  ·  4Comentários

fearphage picture fearphage  ·  3Comentários

stevenmusumeche picture stevenmusumeche  ·  3Comentários

brettz9 picture brettz9  ·  3Comentários

JakobJingleheimer picture JakobJingleheimer  ·  3Comentários