Плохой номер два
```cs
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
Исправленный пример номер два
```cs
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
Исправленный пример номер два. Тест
```cs
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);
}
```
Исправленный пример номер два. FakeItEasy
```cs
[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);
}
```
Интеграционный тест
```cs
new MainLogic(new Db(fakeConnection));
```
Затычки на каком-то уровне. Поверх - настоящая логика
Single Responsibility
```cs
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);
}
```
Чистые функции. Декомпозиция.