Pergunta

Estou criando o teste unitário que precisará comparar dois objetos do mesmo tipo por membro.Decidi usar a biblioteca SemanticComparison para lidar com essa tarefa sem escrever código comparador personalizado.Funciona muito bem ao comparar objetos planos; há problemas quando o objeto contém objetos aninhados que também precisam ser comparados por membros.

public class Outer
{
    public string Name { get; set; }
    public Inner Inner { get; set; }
}

public class Inner
{
    public string Name { get; set; }
    public string Value { get; set; }
}

public class Service
{
    public Outer Method()
    {
        return new Outer()
        {
            Name = "outerName",
            Inner = new Inner()
            {
                Name = "innerName",
                Value = "value1"
            }
        };
    }
}

Isso não funcionará porque o objeto Inner é comparado por referência, não por membro:

    [Test]
    public void SimpleTest1()
    {

        // setup
        var expectedLikeness = new Outer()
        {
            Name = "outerName",
            Inner = new Inner()
            {
                Name = "innerName",
                Value = "value1"
            }
        }.AsSource().OfLikeness<Outer>();

        var sut = new Service();
        // exercise sut
        var actual = sut.Method();
        // verify
        expectedLikeness.ShouldEqual(actual);
    }

Para fazer funcionar, tive que criar um proxy do objeto aninhado para que ele substituísse o padrão igual à implementação.

    [Test]
    public void SimpleTest2()
    {

        // setup
        var expectedLikeness = new Outer()
        {
            Name = "outerName",
            Inner = new Inner()
            {
                Name = "innerName",
                Value = "value1"
            }.AsSource().OfLikeness<Inner>().CreateProxy()
        }.AsSource().OfLikeness<Outer>();

        var sut = new Service();
        // exercise sut
        var actual = sut.Method();
        // verify
        expectedLikeness.ShouldEqual(actual);
    }

Bem, funciona corretamente, mas imagine que após alguma refatoração do código de serviço introduzimos o bug que faz com que a propriedade value da classe Inner seja diferente do valor esperado.O recurso interessante do SemanticComparison é que ele pode registrar o nome do membro que causa a desigualdade.Mas, neste caso, retornará apenas "Inner" como incompatibilidade, e não o nome da propriedade específica na classe Inner.

Estou esquecendo de algo?É possível configurá-lo para poder retornar o membro incompatível real.

Obviamente, isso não é um problema para estruturas de dados simples como neste exemplo, mas pode ser um inconveniente para testar um código da vida real.

Foi útil?

Solução

Como ninguém respondeu, darei minha própria resposta.

Então, parece que você não pode fazer isso OOTB, a menos que escreva algum código extra.Envolvi o código em um conjunto de métodos de extensão.Esses métodos permitem especificar quais propriedades internas/propriedades de coleção devem ser comparadas usando semelhança interna, não por referência.Você não precisa criar nenhum proxy manualmente, tudo é feito internamente por essas extensões.E os resultados de todas as comparações internas são registrados, para que você possa ver exatamente qual membro tem valor inválido.

Aqui está o teste da pergunta com o uso do método de extensão "WithInnerLikeness".

    [Test]
    public void ServiceTest3()
    {
        // setup
        var expected = new Outer()
        {
            Name = "outerName",
            Inner = new Inner()
            {
                Name = "innerName",
                Value = "value2"
            }
        };

        var expectedLikeness = expected.AsSource().OfLikeness<Outer>()
            .WithInnerLikeness(d => d.Inner, s => s.Inner)
            ;

        var sut = new Service();
        // exercise sut
        var actual = sut.Method();
        // verify
        expectedLikeness.ShouldEqual(actual);
    }

Você pode ver que as propriedades de valor dos objetos internos não correspondem, portanto o teste deve falhar.E falha com as seguintes mensagens na saída:

Comparing inner properties using likeness. Source: s => s.Inner Destination: d => d.Inner.
The source and destination values are not equal. Details: The provided value ClassLibrary1.Inner did not match the expected value ClassLibrary1.Inner. The following members did not match:
- Value.

Ploeh.SemanticComparison.LikenessException : The provided value ClassLibrary1.Outer did not match the expected value ClassLibrary1.Outer. The following members did not match:
- Inner.

Você pode encontrar o código-fonte e mais exemplos no github.

https://github.com/jmansar/SemanticComparisonExtensions

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