Pergunta

Zombando de classes seladas pode ser bastante doloroso.Atualmente sou a favor de um Padrão do adaptador para lidar com isso, mas algo continua parece estranho.

Então, qual é a melhor maneira de simular aulas seladas?

Respostas Java são mais que bem-vindas.Na verdade, eu prevejo que a comunidade Java já lida com isso há mais tempo e tem muito a oferecer.

Mas aqui estão algumas das opiniões do .NET:

Foi útil?

Solução

Minha regra geral é que os objetos que preciso simular também devem ter uma interface comum.Eu acho que isso é correto em termos de design e torna os testes muito mais fáceis (e geralmente é o que você obtém se fizer TDD).Mais sobre isso pode ser lido no Google Testing Blog última postagem (Ver ponto 9).

Além disso, tenho trabalhado principalmente em Java nos últimos 4 anos e posso dizer que posso contar nos dedos de uma mão o número de vezes que criei uma aula final (lacrada).Outra regra aqui é que eu sempre deveria ter um bom motivo para lacrar uma classe, em vez de lacrá-la por padrão.

Outras dicas

Para .NET, você poderia usar algo como TipoMock, que usa a API de criação de perfil e permite conectar chamadas para praticamente qualquer coisa.

Acredito que Toupeiras, da Microsoft Research, permite que você faça isso.Na página Moles:

As toupeiras podem ser usadas para desviar qualquer método .NET, incluindo métodos não virtuais/estáticos em tipos selados.

ATUALIZAR: há uma nova estrutura chamada "Fakes" na próxima versão do VS 11 que foi projetada para substituir Moles:

O Estrutura Fakes no Visual Studio 11 é a próxima geração de Moles & Stubs e eventualmente irá substituí-la.No entanto, Fakes é diferente de Moles, portanto, mudar de Moles para Fakes exigirá algumas modificações em seu código.Um guia para esta migração estará disponível posteriormente.

Requisitos:Visual Studio 11 final, .NET 4.5

O problema com TypeMock é que ele desculpa um design ruim.Agora, eu sei que muitas vezes é de outra pessoa design ruim que está escondendo, mas permiti-lo em seu processo de desenvolvimento pode facilmente levar à permissão de seus próprios designs ruins.

Eu acho que se você for usar uma estrutura de simulação, você deve usar uma tradicional (como Moq) e criar uma camada de isolamento em torno da coisa que não pode ser simulada e, em vez disso, simular a camada de isolamento.

Quase sempre evito ter dependências de classes externas no meu código.Em vez disso, prefiro usar um adaptador/ponte para conversar com eles.Dessa forma, estou lidando com minha semântica, e a dor de traduzir fica isolada em uma aula.

Também torna mais fácil mudar minhas dependências no longo prazo.

Me deparei com esse problema recentemente e depois de ler/pesquisar na web, parece que não há uma maneira fácil de contornar, exceto usar outra ferramenta mencionada acima.Ou rude ao lidar com as coisas como eu fiz:

  • Crie uma instância da classe selada sem chamar o construtor.
  • System.Runtime.Serialization.FormatterServices.GetUninitializedObject(instanceType);

  • Atribua valores às suas propriedades/campos via reflexão

  • YourObject.GetType().GetProperty("PropertyName").SetValue(dto, newValue, null);
  • YourObject.GetType().GetField("NomeCampo").SetValue(dto, newValue);

Geralmente sigo o caminho de criar uma interface e uma classe de adaptador/proxy para facilitar a simulação do tipo selado.No entanto, também experimentei pular a criação da interface e tornar o tipo de proxy não selado com métodos virtuais.Isso funcionou bem quando o proxy é realmente uma classe base natural que encapsula e usa parte da classe selada.

Ao lidar com códigos que exigiam essa adaptação, cansei de realizar as mesmas ações para criar a interface e o tipo de proxy então implementei uma biblioteca para automatizar a tarefa.

O código é um pouco mais sofisticado que o exemplo fornecido no artigo que você refere, pois produz um assembly (em vez de código-fonte), permite que a geração de código seja realizada em qualquer tipo e não requer tanta configuração.

Para obter mais informações, consulte esta página.

É perfeitamente razoável zombar de uma classe selada porque muitas classes de estrutura são seladas.

No meu caso, estou tentando zombar da classe MessageQueue do .Net para que eu possa TDD minha lógica de tratamento de exceções elegante.

Se alguém tiver ideias sobre como superar o erro do Moq em relação a "Configuração inválida em um membro não substituível", por favor me avise.

código:

    [TestMethod]
    public void Test()
    {
        Queue<Message> messages = new Queue<Message>();
        Action<Message> sendDelegate = msg => messages.Enqueue(msg);
        Func<TimeSpan, MessageQueueTransaction, Message> receiveDelegate =
            (v1, v2) =>
            {
                throw new Exception("Test Exception to simulate a failed queue read.");
            };

        MessageQueue mockQueue = QueueMonitorHelper.MockQueue(sendDelegate, receiveDelegate).Object;
    }
    public static Mock<MessageQueue> MockQueue
                (Action<Message> sendDelegate, Func<TimeSpan, MessageQueueTransaction, Message> receiveDelegate)
    {
        Mock<MessageQueue> mockQueue = new Mock<MessageQueue>(MockBehavior.Strict);

        Expression<Action<MessageQueue>> sendMock = (msmq) => msmq.Send(It.IsAny<Message>()); //message => messages.Enqueue(message);
        mockQueue.Setup(sendMock).Callback<Message>(sendDelegate);

        Expression<Func<MessageQueue, Message>> receiveMock = (msmq) => msmq.Receive(It.IsAny<TimeSpan>(), It.IsAny<MessageQueueTransaction>());
        mockQueue.Setup(receiveMock).Returns<TimeSpan, MessageQueueTransaction>(receiveDelegate);

        return mockQueue;
    }

Embora atualmente esteja disponível apenas na versão beta, acho que vale a pena ter em mente o calço característica do novo Estrutura falsa (parte de Estúdio Visual 11 Versão beta).

Os tipos Shim fornecem um mecanismo para desviar qualquer método .NET para um delegado definido pelo usuário.Os tipos shim são gerados por código pelo gerador Fakes e usam delegados, que chamamos de tipos shim, para especificar as novas implementações de métodos.Nos bastidores, os tipos de shim usam retornos de chamada que foram injetados em tempo de execução nos corpos do método MSIL.

Pessoalmente, eu estava pensando em usar isso para simular os métodos em classes de estrutura seladas, como DrawingContext.

Existe uma maneira de implementar uma classe selada a partir de uma interface...e zombar da interface?

Algo em mim sente que ter aulas seladas é errado em primeiro lugar, mas sou só eu :)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top