Есть такие задачи, где выгода от юнит-тестов очевидна даже самому упорному тестоотрицателю :)
Наконец я решил начать писать настоящий флэш-блог-движок вместо прототипа, который вы видите сейчас. Важной частью этого блога будет парсер, который преобразует вики разметку (в ней создается, хранится и редактируется статья) в разметку TLF для флэш-версии и в HTML-код для HTML-версии (а потом, может, и в PDF формат).
Вики разметка предполагается довольно стандартная, не отличающаяся от большинства вики-систем. Тем не менее, написать и отладить такой парсер без юнит-тестов -- это большой гемор. А с юнит-тестами -- сплошное удовольствие :)
Вот я сейчас, вечерком сел, пересмотрел доки по регулярным выражениям, и набросал код, который умеет парсить bold и _italic_
Вот как выглядит этот код:
/**
* @author Yura Zhloba
*/
package com.flashdevs.yzh.wikiParser
{
public class Lexeme
{
// properties
private var match : String;
private var openTag : String;
private var closeTag : String;
// constructor
public function Lexeme(match : String, openTag : String, closeTag : String)
{
this.match = match;
this.openTag = openTag;
this.closeTag = closeTag;
}
// methods
public function parse(text : String) : String
{
var ans : String = '';
var regExp : RegExp = new RegExp(match, 'gms');
var res : Object = regExp.exec(text);
var next : int = 0;
while(res != null)
{
ans += text.substring(next, res.index);
ans += openTag;
ans += (res.length > 1) ? res[1] : res[0];
ans += closeTag;
next = res.index + res[0].length;
res = regExp.exec(text);
}
ans += text.substring(next);
return ans;
}
public function toString() : String
{ return 'Lexeme'; }
}
}
/**
* @author Yura Zhloba
*
* parse wiki-text and generate xml-content with TLF
*/
package com.flashdevs.yzh.wikiParser
{
public class WikiParser
{
static public const BOLD_MATCH : String = '\\*([^\\*]+?)\\*';
static public const ITALIC_MATCH : String = '_([^\\*]+?)_';
// properties
private var lexemes : Array;
// constructor
public function WikiParser()
{
lexemes = [
new Lexeme(BOLD_MATCH, '<span fontWeight="bold">', '</span>'),
new Lexeme(ITALIC_MATCH, '<span fontStyle="italic">', '</span>')
];
}
// methods
public function parse(data : String) : String
{
var res : String = data;
for each(var lexeme : Lexeme in lexemes) res = lexeme.parse(res);
return res;
}
public function toString() : String
{ return 'WikiParser'; }
}
}
А вот как выглядят юнит-тесты к нему:
/**
* @author Yura Zhloba
*/
package
{
import com.flashdevs.yzh.wikiParser.Lexeme;
import com.flashdevs.yzh.wikiParser.WikiParser;
import org.flexunit.Assert;
public class TestWikiParser
{
[Test]
public function testLexeme() : void
{
var data : String = 'aaa bbb ccc bbb ddd';
Assert.assertEquals('aaa <open>bbb<close> ccc <open>bbb<close> ddd',
new Lexeme('bbb', '<open>', '<close>').parse(data));
Assert.assertEquals('[aaa] [bbb] [ccc] [bbb] [ddd]',
new Lexeme('\\w+', '[', ']').parse(data));
}
[Test]
public function testBoldLexeme() : void
{
var lexeme : Lexeme = new Lexeme(WikiParser.BOLD_MATCH, '<span fontWeight="bold">', '</span>');
Assert.assertEquals('some <span fontWeight="bold">bold</span> data',
lexeme.parse('some *bold* data'));
Assert.assertEquals('and <span fontWeight="bold">here several words</span> in bold',
lexeme.parse('and *here several words* in bold'));
Assert.assertEquals('one <span fontWeight="bold">two three</span> four ' +
'<span fontWeight="bold"> five six </span> seven ' +
'<span fontWeight="bold">eight</span>',
lexeme.parse('one *two three* four * five six * seven *eight*'));
}
[Test]
public function testBoldAndItalicLexemes() : void
{
var boldLexeme : Lexeme = new Lexeme(WikiParser.BOLD_MATCH, '<span fontWeight="bold">', '</span>');
var italicLexeme : Lexeme = new Lexeme(WikiParser.ITALIC_MATCH, '<span fontStyle="italic">', '</span>');
var data : String = 'here *bold text* and _some italic text_ and *bold and _italic inside_ it*';
var res1 : String = italicLexeme.parse(boldLexeme.parse(data));
var res2 : String = boldLexeme.parse(italicLexeme.parse(data));
Assert.assertEquals(res1, res2);
Assert.assertEquals('here <span fontWeight="bold">bold text</span> ' +
'and <span fontStyle="italic">some italic text</span> ' +
'and <span fontWeight="bold">bold ' +
'and <span fontStyle="italic">italic inside</span> it</span>', res1);
}
[Test]
public function testWikiParser() : void
{
var data : String = 'here *bold text* and _some italic text_ and *bold and _italic inside_ it*';
var parser : WikiParser = new WikiParser();
Assert.assertEquals('here <span fontWeight="bold">bold text</span> ' +
'and <span fontStyle="italic">some italic text</span> ' +
'and <span fontWeight="bold">bold ' +
'and <span fontStyle="italic">italic inside</span> it</span>',
parser.parse(data));
}
}
}
В данной ситуации юнит-тесты -- это, во-первых, самый простой и быстрый способ проверить правильность парсинга, во-вторых, можно придумывать самые изощренные варианты разметки, и все они сохранятся, не потеряются, и все они будут проверяться при каждом запуске тестов.
Начинаем с простых вариантов, добиваемся правильности работы, а потом усложняем, не боясь, что все сломается.
В будущем, если выявится баг в парсере, мы тут же добавим на него тест и пофиксим. И мы будем уверены, что если этот баг появится еще раз, то мы тут же его заметим.
PROFIT :)

Recent comments
5 days 22 hours ago
1 week 1 day ago
1 week 6 days ago
3 weeks 10 hours ago
4 weeks 3 days ago
4 weeks 3 days ago
4 weeks 3 days ago
4 weeks 3 days ago
5 weeks 9 hours ago
5 weeks 3 days ago