Tratamento de testes unitários

Os testes unitários de conectores simples e complexos são uma melhor prática e é altamente recomendado.

O teste unitário é realizado no contexto do SDK de Power Query do Visual Studio. Cada teste é definido como um Fact que tem um nome, um valor esperado e um valor real. Na maioria dos casos, o "valor real" será uma expressão M que testa parte da expressão.

Considere uma extensão muito simples que exporta três funções:

section Unittesting;

shared UnitTesting.ReturnsABC = () => "ABC";
shared UnitTesting.Returns123 = () => "123";
shared UnitTesting.ReturnTableWithFiveRows = () => Table.Repeat(#table({"a"},{{1}}),5);

Esse código de teste unitário é composto por vários Fatos e vários códigos comuns para a estrutura de teste unitário (ValueToText, Fact, Facts, Facts.Summarize). O seguinte código fornece um conjunto de exemplos de fatos (acesse UnitTesting.query.pq para o código comum):

section UnitTestingTests;

shared MyExtension.UnitTest = 
[
    // Put any common variables here if you only want them to be evaluated once

    // Fact(<Name of the Test>, <Expected Value>, <Actual Value>)
    facts = 
    {
        Fact("Check that this function returns 'ABC'",  // name of the test
            "ABC",                                      // expected value
            UnitTesting.ReturnsABC()                    // expression to evaluate (let or single statement)
        ),
        Fact("Check that this function returns '123'",
            "123",
            UnitTesting.Returns123()
        ),
        Fact("Result should contain 5 rows",
            5,
            Table.RowCount(UnitTesting.ReturnTableWithFiveRows())
        ),
        Fact("Values should be equal (using a let statement)",
            "Hello World",
            let
                a = "Hello World"
            in
                a
        )
    },
    report = Facts.Summarize(facts)
][report];

A execução do exemplo no Visual Studio avaliará todos os Fatos e fornecerá um resumo visual das taxas de aprovação:

Exemplo de taxas de aprovação.

A implementação dos testes unitários no início do processo de desenvolvimento do conector permite que você siga os princípios do desenvolvimento orientado por testes. Imagine que você precisa escrever uma função chamada Uri.GetHost que retorna apenas os dados do host de um URI. Você pode começar escrevendo um caso de teste para verificar se a função executa adequadamente a função esperada:

Fact("Returns host from URI",
    "https://bing.com",
    Uri.GetHost("https://bing.com/subpath/query?param=1&param2=hello")
),
Fact("Handles port number appropriately",
    "https://bing.com:8080",
    Uri.GetHost("https://bing.com:8080/subpath/query?param=1&param2=hello")
)

Testes adicionais podem ser gravados para garantir que a função manipule adequadamente os casos extremos.

Uma versão inicial da função pode passar em alguns, mas não em todos os testes:

Uri.GetHost = (url) =>
    let
        parts = Uri.Parts(url)
    in
        parts[Scheme] & "://" & parts[Host]

Alguns testes que falharam.

A versão final da função deve passar em todos os testes unitários. Isso também ajuda a garantir que atualizações futuras da função não removam acidentalmente nenhuma de suas funcionalidades básicas.

Todos os testes serão aprovados.