feat: improved tests

pull/111/head
alestiago 4 years ago
parent 27f6d839cc
commit 27e12148f8

@ -78,13 +78,7 @@ class BottomWall extends Wall {
class BottomWallBallContactCallback extends ContactCallback<Ball, BottomWall> {
@override
void begin(Ball ball, BottomWall wall, Contact contact) {
ball.shouldRemove = true;
// TODO(alestiago): replace with .firstChild when available.
late final BallController? controller;
final children = ball.children.whereType<BallController>();
controller = children.isEmpty ? null : children.first;
if (controller != null) controller.lost();
ball.children.whereType<BallController>().first.lost();
}
}

@ -0,0 +1,144 @@
// ignore_for_file: cascade_invocations
import 'package:bloc_test/bloc_test.dart';
import 'package:flame_test/flame_test.dart';
import 'package:flutter/painting.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart';
import '../../helpers/helpers.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final flameTester = FlameTester(PinballGameTest.create);
group('BallController', () {
late Ball ball;
setUp(() {
ball = Ball(baseColor: const Color(0xFF00FFFF));
});
flameTester.test(
'lost removes ball',
(game) async {
await game.add(ball);
final controller = BallController(ball);
await controller.attach();
await game.ready();
controller.lost();
await game.ready();
expect(game.contains(ball), isFalse);
},
);
});
group('PlungerBallController', () {
group('lost', () {
late GameBloc gameBloc;
late Ball ball;
setUp(() {
gameBloc = MockGameBloc();
ball = Ball(baseColor: const Color(0xFF00FFFF));
whenListen(
gameBloc,
const Stream<GameState>.empty(),
initialState: const GameState.initial(),
);
});
final tester = flameBlocTester<PinballGame>(
game: PinballGameTest.create,
gameBloc: () => gameBloc,
);
tester.widgetTest(
'removes ball',
(game, tester) async {
await game.add(ball);
final controller = PlungerBallController(ball);
await controller.attach();
await game.ready();
controller.lost();
await game.ready();
expect(game.contains(ball), isFalse);
},
);
tester.widgetTest(
'adds BallLost to GameBloc',
(game, tester) async {
final controller = PlungerBallController(ball);
await controller.attach();
await game.add(ball);
await game.ready();
controller.lost();
verify(() => gameBloc.add(const BallLost())).called(1);
},
);
tester.widgetTest(
'adds a new ball if the game is not over',
(game, tester) async {
final controller = PlungerBallController(ball);
await controller.attach();
await game.add(ball);
await game.ready();
final previousBalls = game.descendants().whereType<Ball>();
controller.lost();
await game.ready();
final currentBalls = game.descendants().whereType<Ball>();
expect(
previousBalls.length,
equals(currentBalls.length),
);
},
);
tester.widgetTest(
'no ball is added on game over',
(game, tester) async {
whenListen(
gameBloc,
const Stream<GameState>.empty(),
initialState: const GameState(
score: 10,
balls: 1,
activatedBonusLetters: [],
activatedDashNests: {},
bonusHistory: [],
),
);
final controller = BallController(ball);
await controller.attach();
await game.add(ball);
await game.ready();
final previousBalls = game.descendants().whereType<Ball>();
controller.lost();
await game.ready();
final currentBalls = game.descendants().whereType<Ball>();
expect(
currentBalls.length,
equals(
(previousBalls.toList()..remove(ball)).length,
),
);
},
);
});
});
}

@ -1,87 +0,0 @@
// ignore_for_file: cascade_invocations
import 'package:bloc_test/bloc_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart';
import '../../helpers/helpers.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group('Ball', () {
group('lost', () {
late GameBloc gameBloc;
setUp(() {
gameBloc = MockGameBloc();
whenListen(
gameBloc,
const Stream<GameState>.empty(),
initialState: const GameState.initial(),
);
});
final tester = flameBlocTester(gameBloc: () => gameBloc);
tester.testGameWidget(
'adds BallLost to GameBloc',
setUp: (game, tester) async {
await game.ready();
},
verify: (game, tester) async {
game.children.whereType<Ball>().first.controller.lost();
await tester.pump();
verify(() => gameBloc.add(const BallLost())).called(1);
},
);
tester.testGameWidget(
'resets the ball if the game is not over',
setUp: (game, tester) async {
await game.ready();
game.children.whereType<Ball>().first.controller.lost();
await game.ready(); // Making sure that all additions are done
},
verify: (game, tester) async {
expect(
game.children.whereType<Ball>().length,
equals(1),
);
},
);
tester.testGameWidget(
'no ball is added on game over',
setUp: (game, tester) async {
whenListen(
gameBloc,
const Stream<GameState>.empty(),
initialState: const GameState(
score: 10,
balls: 1,
activatedBonusLetters: [],
activatedDashNests: {},
bonusHistory: [],
),
);
await game.ready();
game.children.whereType<Ball>().first.controller.lost();
await tester.pump();
},
verify: (game, tester) async {
expect(
game.children.whereType<Ball>().length,
equals(0),
);
},
);
});
});
}

@ -194,10 +194,15 @@ void main() {
});
group('bonus letter activation', () {
final gameBloc = MockGameBloc();
final tester = flameBlocTester(gameBloc: () => gameBloc);
late GameBloc gameBloc;
final tester = flameBlocTester(
// TODO(alestiago): Use TestGame once BonusLetter has controller.
game: PinballGameTest.create,
gameBloc: () => gameBloc,
);
setUp(() {
gameBloc = MockGameBloc();
whenListen(
gameBloc,
const Stream<GameState>.empty(),
@ -236,8 +241,10 @@ void main() {
initialState: state,
);
final bonusLetter = BonusLetter(letter: '', index: 0);
await game.add(bonusLetter);
await game.ready();
final bonusLetter = game.descendants().whereType<BonusLetter>().first;
bonusLetter.activate();
await game.ready();
},
@ -257,15 +264,19 @@ void main() {
bonusHistory: [],
);
final bonusLetter = BonusLetter(letter: '', index: 0);
await game.add(bonusLetter);
await game.ready();
final bonusLetter = game.descendants().whereType<BonusLetter>().first;
bonusLetter.activate();
bonusLetter.onNewState(state);
await tester.pump();
},
verify: (game, tester) async {
final bonusLetter = game.descendants().whereType<BonusLetter>().first;
// TODO(aleastiago): Look into making `testGameWidget` pass the
// subject.
final bonusLetter = game.descendants().whereType<BonusLetter>().last;
expect(
bonusLetter.children.whereType<ColorEffect>().length,
equals(1),

@ -59,7 +59,10 @@ void main() {
group('listenWhen', () {
final gameBloc = MockGameBloc();
final tester = flameBlocTester(gameBloc: () => gameBloc);
final tester = flameBlocTester(
game: TestGame.new,
gameBloc: () => gameBloc,
);
setUp(() {
whenListen(
@ -71,12 +74,8 @@ void main() {
tester.testGameWidget(
'listens when a Bonus.dashNest is added',
setUp: (game, tester) async {
await game.ready();
},
verify: (game, tester) async {
final flutterForest =
game.descendants().whereType<FlutterForest>().first;
final flutterForest = FlutterForest();
const state = GameState(
score: 0,
@ -96,7 +95,11 @@ void main() {
group('DashNestBumperBallContactCallback', () {
final gameBloc = MockGameBloc();
final tester = flameBlocTester(gameBloc: () => gameBloc);
final tester = flameBlocTester(
// TODO(alestiago): Use TestGame.new once a controller is implemented.
game: PinballGameTest.create,
gameBloc: () => gameBloc,
);
setUp(() {
whenListen(
@ -118,8 +121,9 @@ void main() {
final contactCallback = DashNestBumperBallContactCallback();
contactCallback.begin(dashNestBumper, MockBall(), MockContact());
verify(() => gameBloc.add(DashNestActivated(dashNestBumper.id)))
.called(1);
verify(
() => gameBloc.add(DashNestActivated(dashNestBumper.id)),
).called(1);
},
);
});

@ -2,7 +2,6 @@
import 'dart:collection';
import 'package:bloc_test/bloc_test.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flame_test/flame_test.dart';
import 'package:flutter/services.dart';
@ -189,22 +188,14 @@ void main() {
group('PlungerAnchorPrismaticJointDef', () {
const compressionDistance = 10.0;
final gameBloc = MockGameBloc();
late Plunger plunger;
setUp(() {
whenListen(
gameBloc,
const Stream<GameState>.empty(),
initialState: const GameState.initial(),
);
plunger = Plunger(
compressionDistance: compressionDistance,
);
});
final flameTester = flameBlocTester(gameBloc: () => gameBloc);
group('initializes with', () {
flameTester.test(
'plunger body as bodyA',

@ -1,4 +1,3 @@
import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
@ -7,14 +6,6 @@ import 'package:pinball_components/pinball_components.dart';
import '../../helpers/helpers.dart';
class MockGameBloc extends Mock implements GameBloc {}
class MockPinballGame extends Mock implements PinballGame {}
class FakeContact extends Fake implements Contact {}
class FakeGameEvent extends Fake implements GameEvent {}
class FakeScorePoints extends BodyComponent with ScorePoints {
@override
Body createBody() {
@ -30,16 +21,12 @@ void main() {
late PinballGame game;
late GameBloc bloc;
late Ball ball;
late ComponentSet componentSet;
late BallController ballController;
late FakeScorePoints fakeScorePoints;
setUp(() {
game = MockPinballGame();
bloc = MockGameBloc();
ball = MockBall();
componentSet = MockComponentSet();
ballController = MockBallController();
fakeScorePoints = FakeScorePoints();
});
@ -51,13 +38,9 @@ void main() {
test(
'emits Scored event with points',
() {
when(() => componentSet.whereType<BallController>())
.thenReturn([ballController]);
when(() => ball.children).thenReturn(componentSet);
when<Forge2DGame>(() => ballController.gameRef).thenReturn(game);
when<GameBloc>(game.read).thenReturn(bloc);
BallScorePointsCallback().begin(
BallScorePointsCallback(game).begin(
ball,
fakeScorePoints,
FakeContact(),
@ -71,19 +54,5 @@ void main() {
},
);
});
group('end', () {
test("doesn't add events to GameBloc", () {
BallScorePointsCallback().end(
ball,
fakeScorePoints,
FakeContact(),
);
verifyNever(
() => bloc.add(any()),
);
});
});
});
}

@ -1,14 +1,14 @@
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flame_test/flame_test.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:pinball/game/game.dart';
import 'helpers.dart';
FlameTester<PinballGame> flameBlocTester({
FlameTester<T> flameBlocTester<T extends Forge2DGame>({
required T Function() game,
required GameBloc Function() gameBloc,
}) {
return FlameTester<PinballGame>(
PinballGameTest.create,
return FlameTester<T>(
game,
pumpWidget: (gameWidget, tester) async {
await tester.pumpWidget(
BlocProvider.value(

@ -0,0 +1,7 @@
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:mocktail/mocktail.dart';
import 'package:pinball/game/game.dart';
class FakeContact extends Fake implements Contact {}
class FakeGameEvent extends Fake implements GameEvent {}

@ -6,7 +6,9 @@
// license that can be found in the LICENSE file or at
export 'builders.dart';
export 'extensions.dart';
export 'fakes.dart';
export 'key_testers.dart';
export 'mocks.dart';
export 'navigator.dart';
export 'pump_app.dart';
export 'test_game.dart';

@ -0,0 +1,7 @@
import 'package:flame_forge2d/flame_forge2d.dart';
class TestGame extends Forge2DGame {
TestGame() {
images.prefix = '';
}
}
Loading…
Cancel
Save