On Github a10nik / myf-testing
Артем Десятников
Самый интуитивный метод
Иногда нельзя иначе
иначе тест ТьюрингаПервого рода — посчитать плохую программу хорошей
Второго рода — посчитать хорошую программу плохой
Тестирование минимальных кусочков приложения по-отдельности.
Надо сделать их независимыми
падают только если ошибка в коде кусочка. удобно искать. обычно - только при разработке кусочка или внесении изменений в кусочек. иногда - при рефакторингахclass TodoList { private TodoItem[] items; public TodoList() { this.items = Db.GetTodoItems(); } } void MainLogic() { var list = new TodoList(); Render(list); }
class TodoList { private TodoItem[] items; public TodoList() { this.items = Db.GetTodoItems(); } } void Test() { var list = new TodoList(); ??? }
Dependency Injection
class TodoList { private TodoItem[] items; public TodoList(TodoItem[] items) { this.items = items; } } void MainLogic() { var db = new Db("login", "pass", catalog: "items"); var items = db.GetTodoItems(); var list = new TodoList(items); Render(list); } void Test() { var list = new TodoList(new[] { new TodoItem() { Text = "Первая тудушка", Done = false } }); var rendered = Render(list); Assert.That(rendered, Contains.Substring("Первая тудушка")); }
[TestFixture] public class TodoListTest { [Test] public void HasNothingToDoWhenEmpty() { var list = new TodoList(new TodoItem[] {}); Assert.That(list.HasSmthToDo, Is.False); } }
describe("todo list", () => { it("has nothing to do when empty", () => { let list = new TodoList([]); expect(list.hasSmthToDo).to.be.false; }); });
Assert.AreNotEqual(5, 2 + 2); // vs Assert.That(2 + 2, Is.Not.EqualTo(5)); Assert.That(SomeMethod, Throws.TypeOf() .With.Property("Parameter").EqualTo("myParam"));
class Db { ... public TodoItem[] GetTodoItems() { return new DbConnection(login, password, catalog) .Query("select * from todos") .Select(row => new TodoItem { Text = row["text"], Done = row["done"] == "1" }); } public void SaveTodoItems(TodoItem[] items) { new DbConnection(login, password, catalog) .Query("insert or update items " + ...)); } }
Dependency Inversion
class Db { private IDbConnection connection; ... public TodoItem[] GetTodoItems() { return connection .Query("select * from todos") .Select(row => new TodoItem { Text = row["text"], Done = row["done"] == "1" }); } public void SaveTodoItems(TodoItem[] items) { connection.Query("insert or update items " + ...); } }
Dependency Inversion
class TestEmptyConnection : IDbConnection { public RowSet Query(string query) { return new RowSet(); } public void Dispose() {} } [Test] void AllDoneWhenListIsEmpty() { var db = new Db(new TestEmptyConnection()); Assert.That(db.GetTodoItems(), Is.Empty); }
[Test] void DbYieldsEmptyItemListWhenRowSetIsEmpty() { var fakeConnection = A.Fake(); A.CallTo(() => fakeConnection.Query("select * from todos")) .Returns(new RowSet()); var db = new Db(fakeItemProvider); Assert.That(db.GetTodoItems(), Is.Empty); }
new MainLogic(new Db(fakeConnection));
Затычки на каком-то уровне. Поверх - настоящая логика
class DbUtils { public TodoItem RowToTodoItem(Row row) { ... } public string ToUpdateQuery(TodoItem[] items) { ... } } [Test] void RowToTodoItemConvertsSimpleRow() { var row = new Row(); row.Add("done", "0"); row.Add("text", "hello"); var todoItem = DbUtils.RowToTodoItem(row); Assert.That(todoItem.Text, Is.EqualTo("hello")); Assert.That(todoItem.Done, Is.False); }
Чистые функции. Декомпозиция.
Тестирование в браузере
хрупкие. и ошибки расплывчатые