Digamos que estou implementando algo simples, como pesquisar uma lista / matriz classificada. A função (em c #) seria semelhante a:
static int FindIndex(int[] sortedList, int i);
Eu poderia implementar e testar isso em termos de funcionalidade, mas, por razões óbvias, eu normalmente preferiria uma pesquisa binária a uma pesquisa linear ou algo intencionalmente estúpido.
Portanto, minha pergunta é: devemos tentar escrever testes que garantam desempenho em termos de complexidade algorítmica e, em caso afirmativo, como?
Comecei a argumentar nos dois lados da parte "você deveria" desta pergunta, mas eu gostaria de ver o que as pessoas dizem sem meus argumentos para induzi-las.
Em termos de "como", isso fica muito interessante :) Você pode parametrizar o operador de comparação e fazer um teste cujo operador de comparação conta comparações ou algo parecido. Mas só porque você pode, não significa que você deveria ...
Alguém mais considerou isso (provavelmente)? Obrigado.
fonte
Respostas:
A complexidade algorítmica é uma construção teórica e, como tal, é melhor "testada" com um lápis e papel. Não pode ser utilmente testado mecanicamente.
O desempenho absoluto pode ser testado mecanicamente e pode fazer testes de unidade úteis. Se o desempenho for importante, você poderá especificar um limite: "essa consulta não deve demorar mais de 50 ms para ser executada em 10 6 números e não mais que 60ms em 10 7 números". Para o qual você pode construir um teste de unidade.
O usuário final não se importa se seu algoritmo é linear ou logarítmico; eles se importam se a interface do usuário ainda responde instantaneamente, mesmo quando possuem um ano de dados no aplicativo.
fonte
Embora eu não tenha certeza se essa ferramenta será particularmente útil para testes de unidade, o artigo "Complexidade computacional empírica" de Goldsmith, Aiken e Wilkerson descreve um método para instrumentar código e observar seu comportamento dinâmico em um conjunto de várias entradas para empiricamente derivar sua complexidade assintótica. O programa descrito no documento é de código aberto e está disponível aqui .
Espero que isto ajude!
fonte
O principal é experimentá-lo com big data e ver se leva muito tempo.
Na minha experiência de ajuste de desempenho, como neste exemplo , o que acontece é que, se algum algoritmo é (por exemplo) O (n ^ 2), pode ser ótimo, desde que a porcentagem de tempo que leva nunca chegue ao radar.
No entanto, quando é fornecido um conjunto de dados de um tamanho que pode não ser visto, mas uma vez por ano, a fração do tempo total sugado por esse algoritmo pode se tornar catastroficamente dominante.
Se você pode fazer isso acontecer nos testes, isso é uma coisa muito boa, porque é extremamente fácil encontrar o problema, como se fosse um loop infinito real.
fonte
Eu não acho que o que você quer fazer é Teste de Unidade.
AFAIK, o teste de unidade é apenas para garantir que o código faça o que deve fazer e não se concentre no desempenho.
Existem outros tipos de ferramentas e padrões para medir o desempenho. Um dos quais me lembro agora é o teste de aceitação focado em requisitos não funcionais.
Existem poucos outros como testes de desempenho (que usam testes de estresse, testes de carga, etc.).
Você também pode usar algumas ferramentas de estresse junto com uma ferramenta de construção (ant, studio de criação automatizada) como parte de suas etapas de implantação (é o que eu faço).
Portanto, a resposta curta é não, você não deve se preocupar com isso ao testar um código por unidade.
fonte
Passar no comparador e manter o controle do número de vezes que é chamado funcionará com propósitos simples, como verificar se o número de comparações ao fazer uma pesquisa em uma entrada fixa (por exemplo
new int[] { 1,2,3, ... , 1024 }
) permanece abaixo de 10. Isso será pelo menos Esclareça suas intenções sobre como o algoritmo deve se comportar.Não acho que os testes de unidade sejam o caminho certo para verificar se seu algoritmo é O (log n); isso exigiria muita geração aleatória de dados, algum ajuste de curva e provavelmente estatísticas genéricas para determinar se vários pontos de dados se encaixam no tempo de execução esperado. (Para esse algoritmo, provavelmente é possível, mas se você começar a classificar, etc., será difícil atingir repetidamente os piores cenários).
fonte