{"D", 500},
{"M", 1000}
};
public int Converte(string numeroEmRomano)
{
return tabela[numeroEmRomano];
}
}
Ambos os testes continuam passando. Passaremos agora para um segundo ce-
nário: dois símbolos em sequência, como por exemplo, II ou XX. Começando
novamente pelo teste, temos:
[Test]
public void DeveEntenderDoisSimbolosComoII()
{
ConversorDeNumeroRomano romano = new ConversorDeNumeroRomano();
int numero = romano.Converte("II");
Assert.AreEqual(2, numero);
}
Para fazer o teste passar de maneira simples, é possível simplesmente adicionar
os símbolos II na tabela:
23
3.2. O primeiro teste
Casa do Código
private static Dictionary<string, int> tabela =
new Dictionary<string, int>() {
{"I", 1},
{"II", 2},
{"V", 5},
{"X", 10},
{"L", 50},
{"C", 100},
{"D", 500},
{"M", 1000}
};
O teste passa. Mas, apesar de simples, essa não parece uma boa ideia de imple-
mentação: seria necessário incluir todos os possíveis símbolos nessa tabela, o que
não faz sentido.
É hora de refatorar esse código novamente. Uma possível solução seria iterar em
cada um dos símbolos no numeral romano e acumular seu valor; ao final, retorna
o valor acumulado. Para isso, é necessário mudar a tabela para guardar somente
os símbolos principais da numeração romana. Uma possível implementação deste
algoritmo seria:
private static Dictionary<string, int> tabela =
new Dictionary<char, int>() {
{'I', 1},
{'V', 5},
{'X', 10},
{'L', 50},
{'C', 100},
{'D', 500},
{'M', 1000}
};
public int Converte(string numeroEmRomano)
{
int acumulador = 0;
for(int i = 0; i < numeroEmRomano.Length; i++)
{
acumulador += tabela[numeroEmRomano[i]];
}
24
Casa do Código
Capítulo 3. Introdução ao Test-Driven Development
return acumulador;
}
De String para Char?
Repare que o tipo da chave no mapa mudou de String para Character.
Como o algoritmo captura letra por letra da variável numeroEmRomano,
usando o método charAt(), que devolve um char, a busca do símbolo
fica mais direta.
Os três testes continuam passando. E, dessa forma, resolvemos o problema de
dois símbolos iguais em seguida. O próximo cenário são quatro símbolos, dois a
dois, como por exemplo, XXII, que deve resultar em 22. O teste:
[Test]
public void DeveEntenderQuatroSimbolosDoisADoisComoXXII()
{
ConversorDeNumeroRomano romano = new ConversorDeNumeroRomano();
int numero = romano.Converte("XXII");
Assert.AreEqual(22, numero);
}
Esse teste já passa sem que precisemos fazer qualquer alteração. O algoritmo
existente até então já resolve o problema. Vamos então para o próximo cenário: nú-
meros como IV ou IX, onde não basta apenas somar os símbolos existentes.
Novamente, começando pelo teste:
[Test]
public void DeveEntenderNumerosComoIX()
{
ConversorDeNumeroRomano romano = new ConversorDeNumeroRomano();
int numero = romano.Converte("IX");
Assert.AreEqual(9, numero);
}
Para fazer esse teste passar, é necessário pensar um pouco melhor sobre o pro-
blema. Repare que os símbolos em um numeral romano, da direita para a esquerda,
sempre crescem. Quando um número a esquerda é menor do que seu vizinho a di-
reita, esse número deve então ser subtraído ao invés de somado no
acumulador. Esse
algoritmo, em código:
25
3.2. O primeiro teste
Casa do Código
public int Converte(String numeroEmRomano)
{
int acumulador = 0;
int ultimoVizinhoDaDireita = 0;
for(int i = numeroEmRomano.Length - 1; i >= 0; i--)
{
// pega o inteiro referente ao simbolo atual
int atual = tabela[numeroEmRomano[i]];
// se o da direita for menor, o multiplicaremos
// por -1 para torná-lo negativo
int multiplicador = 1;
if(atual < ultimoVizinhoDaDireita) multiplicador = -1;
acumulador +=
tabela[numeroEmRomano[i]] * multiplicador;
// atualiza o vizinho da direita
ultimoVizinhoDaDireita = atual;
}
return acumulador;
}
Os testes agora passam. Mas veja, existe código repetido ali. Na linha em que
o acumulador é somado com o valor atual, tabela[numeroEmRomano[i]] pode ser
substituído pela variável atual. Melhorando o código, temos:
acumulador += atual * multiplicador;
A refatoração foi feita com sucesso, já que os testes continuam passando. Ao
próximo cenário: numeral romano que contenha tanto números invertidos, como
IV, e dois símbolos lado a lado, como XX. Por exemplo, o número XXIV, que
representa o número 24.
Começando pelo teste:
[Test]
public void DeveEntenderNumerosComplexosComoXXIV()
{
ConversorDeNumeroRomano romano = new ConversorDeNumeroRomano();
int numero = romano.Converte("XXIV");
26
Casa do Código
Capítulo 3. Introdução ao Test-Driven Development
Assert.AreEqual(24, numero);
}
Esse teste já passa; o algoritmo criado até então já atende o cenário do teste.
Ainda há outros cenários que poderiam ser testados, mas já fizemos o suficiente para
discutir sobre o assunto.
3.3
Refletindo sobre o assunto
De maneira mais abstrata, o ciclo que foi repetido ao longo do processo de desen-
volvimento da classe acima foi:
Escrevemos um teste de unidade para uma nova funcionalidade;