Initial commit

main
Christoph Giess 2023-02-13 11:42:22 +01:00
parent e1da53cbf0
commit e74aff4b2e
12 changed files with 283 additions and 1 deletions

View File

@ -1,2 +1,5 @@
# dart_mock # Beispiel Programmieren gegen Interfaces
* `dart run` - Startet Programm mit Sqlite-Backend
* `dart test` - Testet mit Map-Backend

View File

@ -0,0 +1,29 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at
# https://dart-lang.github.io/linter/lints/index.html.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options

43
bin/mock.dart 100644
View File

@ -0,0 +1,43 @@
import 'package:mock/person.dart';
import 'package:mock/business.dart';
import 'package:mock/person_data_access_map.dart';
import 'package:mock/person_data_access_sqlite.dart';
/*
@startuml
class Business {
- PersonDataAccessMap backend
}
PersonDataAccessMap <-left- Business : uses
class PersonDataAccessMap {
- Map<int, Person> map
+ store(Person p): void
+ retrieve(int id): Person
+ retrieveAll(): List<Person>
}
class PersonDataAccessSqlite implements PersonDataAccessMap {
- Sqlite db
+ store(Person p): void
+ retrieve(int id): Person
+ retrieveAll(): List<Person>
}
@enduml
*/
void main() {
PersonDataAccessMap backend = PersonDataAccessSqlite("sqlite3.db");
Business b = Business(backend);
List<Person> persons = b.getAllPersons();
int personCount = persons.length;
print("We know $personCount persons");
int nextPersonId = ++personCount;
b.addPerson(Person(nextPersonId, "A New Person"));
print("Now we know ${b.getAllPersons().length} persons");
backend.close();
}

14
lib/business.dart 100644
View File

@ -0,0 +1,14 @@
import 'person.dart';
import 'person_data_access_map.dart';
class Business {
final PersonDataAccessMap _backend;
Business(this._backend);
void addPerson(Person p) => _backend.store(p);
bool existsPersonId(int id) => _backend.retrieve(id) != null;
List<Person> getAllPersons() => _backend.retrieveAll();
}

9
lib/person.dart 100644
View File

@ -0,0 +1,9 @@
class Person {
final int id;
final String name;
const Person(this.id, this.name);
@override
String toString() => "Person: $name ($id)";
}

View File

@ -0,0 +1,13 @@
import 'person.dart';
class PersonDataAccessMap {
final Map<int, Person> _persons = {};
void store(Person p) => _persons[p.id] = p;
Person? retrieve(int personId) => _persons[personId];
List<Person> retrieveAll() => _persons.values.toList();
void close() {}
}

View File

@ -0,0 +1,48 @@
import 'person.dart';
import 'package:sqlite3/sqlite3.dart';
import 'person_data_access_map.dart';
class PersonDataAccessSqlite implements PersonDataAccessMap {
final String fileName;
final Database db;
PersonDataAccessSqlite(this.fileName) : db = sqlite3.open(fileName) {
try {
// when select fails due to missing table ...
db.execute('SELECT count(*) from persons');
} catch (e) {
// ... create it
db.execute('''CREATE TABLE persons (
id INTEGER NOT NULL PRIMARY KEY,
name TEXT NOT NULL);''');
}
}
@override
void store(Person p) {
final stmt = db.prepare('INSERT INTO persons (id, name) VALUES (?, ?)');
stmt.execute([p.id, p.name]);
stmt.dispose();
}
@override
Person? retrieve(int id) {
final ResultSet resultSet =
db.select('SELECT * FROM persons WHERE id = ?', [id]);
return resultSet.isEmpty
? null
: Person(resultSet.first['id'], resultSet.first['name']);
}
@override
List<Person> retrieveAll() {
final ResultSet resultSet = db.select('SELECT * FROM persons');
return resultSet.map((row) => Person(row['id'], row['name'])).toList();
}
@override
void close() {
db.dispose();
}
}

14
mock.iml 100644
View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.pub" />
<excludeFolder url="file://$MODULE_DIR$/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/build" />
</content>
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Dart SDK" level="project" />
<orderEntry type="library" name="Dart Packages" level="project" />
</component>
</module>

21
mock.puml 100644
View File

@ -0,0 +1,21 @@
@startuml
class Business {
- PersonDataAccess backend
}
PersonDataAccess <-left- Business : uses
interface PersonDataAccess {
+ store(Person p): void
+ retrieve(int id): Person
+ retrieveAll(): List<Person>
}
class PersonDataAccessMap implements PersonDataAccess {
- Map<int, Person> map
}
class PersonDataAccessSqlite implements PersonDataAccess {
- Sqlite db
}
@enduml

13
pubspec.yaml 100644
View File

@ -0,0 +1,13 @@
name: mock
description: A simple Mock example
version: 1.0.0
environment:
sdk: '>=2.18.0 <3.0.0'
dev_dependencies:
lints: ^2.0.0
test:
dependencies:
sqlite3: ^1.2.0

View File

@ -0,0 +1,39 @@
import 'package:mock/person_data_access_map.dart';
import 'package:test/test.dart';
import 'package:mock/person.dart';
import 'package:mock/business.dart';
class TestPersonBackend extends PersonDataAccessMap {
TestPersonBackend() {
store(Person(1, "Mr. X"));
store(Person(2, "Ms. Y"));
}
}
void main() {
group('Backend', () {
PersonDataAccessMap? backend;
tearDownAll(() {
backend?.close();
});
group('Empty', () {
final PersonDataAccessMap backend = PersonDataAccessMap();
final Business business = Business(backend);
test('Initial size', () {
expect(business.getAllPersons().length, 0);
});
});
group('Filled', () {
final PersonDataAccessMap backend = TestPersonBackend();
final Business business = Business(backend);
test('Initial size', () {
expect(business.getAllPersons().length, 2);
});
});
});
}

View File

@ -0,0 +1,36 @@
import 'package:test/test.dart';
import 'package:mock/person.dart';
void main() {
group('Person properties', () {
final Person p1 = Person(1, "Dummy User");
setUp(() {
// runs before each test;
print("Set up");
});
tearDown(() {
// runs after each test;
print("Tear down");
});
test('id', () {
expect(p1.id, 1);
});
test('name', () {
expect(p1.id, 1);
});
});
group('Comparing persons', () {
final Person p1 = Person(1, "One person");
final Person p2 = Person(2, "Another person");
test('Same object', () {
expect(p1 == p1, true);
});
test('Different objects', () {
expect(p1 != p2, true);
});
});
}