Mandatory 3
Test Stubs
State
Abstract Factory
Do not panic!
dSoftArk is about
Good analyzable design
not about
HotCiv!
Henrik Bærbak Christensen
2
Ecosense Karibu framework
Henrik Bærbak Christensen
3
Stubs – allow us to test!
Henrik Bærbak Christensen
4
Happy path test
Send the objects
Validate they are
stored in the DB
Henrik Bærbak Christensen
5
... on test doubles...
Henrik Bærbak Christensen
6
... And simulate failure situations
Henrik Bærbak Christensen
7
Back to HotCiv
EpsilonCiv needs a die roll
– Randomness makes auto testing inefficient
– Stub the die!
– Make a ‘PredictableDieStrategy’ with a
• void setSequence(int[] dieValuesToRoll);
– ... And of course a RealDieStrategy = random die
And – inject the proper strategy for testing
Henrik Bærbak Christensen
8
Which one is the Test Stub?
Henrik Bærbak Christensen
9
This is not Abstract Factory!
Henrik Bærbak Christensen
10
This is not Abstract Factory!
Question:
How to reconfigure at
run-time?
Henrik Bærbak Christensen
11
AbsFactory – UML clutter...
Henrik Bærbak Christensen
12
Abstract Factory Hierarchy
Question:
– Interface: CivFactory
– Subclass: AlphaFactory implements CivFactory
– ??: BetaFactory extends AlphaFactory
Fine – Beta IS-A Alpha with some changes, so the
subclass hierarchy works out OK – but naming bad!
<<Interface>> Figure
– <<abstract>> AbstractFigure
– RectangleFigure, CircleFigure, LineFigure,... Extend
AbstractFigure
Henrik Bærbak Christensen
13
Abstraction and parameterization
When we introduce Green and Yellow player?
Henrik Bærbak Christensen
14
Design is About Being Consistent!
If you decide to use Observer for you
WinnerStrategy to solve ZetaCiv...
Then you refactor this decision into
existence consistently – or die the ‘if hell’
Henrik Bærbak Christensen
15
Remember: Refactor
Henrik Bærbak Christensen
16
What can I do?
Henrik Bærbak Christensen
17
Appears General – but is not
Henrik Bærbak Christensen
18
Curiosities
Henrik Bærbak Christensen
19
State – and annoying state!
Who stores what?
Attacks won by player
Henrik Bærbak Christensen
20
Problem statement
When doing compositional designs we
– Cut behaviour that is often otherwise in the same
abstraction, and therefore have access to the same
state (i.e. The same set of instance variables)...
• Parametric: all in the same class
• Polymorphic: subclasses still contain all of superclass var.
– ... Into multiple objects
But how do they share/exchange state!!!
Henrik Bærbak Christensen
21
Example
WinnerStrategy: Algorithm to determine winner
Based upon knowledge of
–
–
–
–
Alpha:
Beta:
Epsilon:
Zeta:
The age (correlates to rounds)
Owner of all cities
Attacks won by player
Rounds+Beta+Epsilon’
• Epsilon’ = counting only starts after 20 rounds
But who is responsible for ”knowing it”?
Henrik Bærbak Christensen
22
Example
Who should know it?
– Game or the WinnerStrategy or some third object?
–
–
–
–
Game/WinnerS: Number of rounds played/age
Game:
Owner of all cities
WinnerS:
Attacks won by player
WinnerS:
Counting only starts after 20 rounds
Known by Game
Not really known by the Game
Henrik Bærbak Christensen
23
Solution 1
Let the GameImp store all this state + provide
accessor methods for them
Fine for
– Game/WinnerS: Number of rounds played
– Game:
Owner of all cities
– See Finn’s note on the weekplan
But should game count attacks?
– Augment the Game interface? Or GameImpl?
• See Finn’s discussion of ’Private Interfaces’
– Change game to suit a single strategy?
Henrik Bærbak Christensen
24
Solution 2
Augment the WinnerStrategy interface, to capture state
– incrementRoundCount();
– incrementAttacksWon(Player p);
– cityOwnerChanged(Position p);
– All info local to the winner algorithm (cohesion)
– No irrelevant data captured in Game (cohesion)
– No accessor methods introduced in Game only for the strategy
– GameImpl has to invoke these methods (and only once!)
• (low cohesion)
– Many strategies do not need that info anyway
• Well-known property of Strategy
– Not open to further weird strategies
Henrik Bærbak Christensen
25
Solution 3 (bit similar to 2)
Rather complex solution but with merits...
– Create a GameEventObserver, let GameImpl call its methods:
• cityCreated(Position p)
• attackPerformed(Unit winner);
• roundIncrement();
Let our strategy register as observer of the game
– Can do its own counting = no irrelevant state in Game
– But GameImpl has to call ‘notifyAttackWonBy(p)’
– Can be used for other purposes, like scoring graphs
– Can probably suit new strategiest that count other stuff...
Henrik Bærbak Christensen
26
Scores...
Basically we either
– 1) Add strategy specific state into Game
• That is not used by most variants
• State has to be properly maintained (remember to incr. Battel
counter)
– 2) Add strategy specific method calls into Game
• That lowers readability of game
• That obey a sensitive protocol
– i.e. ’global analysis’ of GameImpl to ensure that
’incrementBattleCount()’ is called once and only once
• (Observer solution is basically a variant of this theme)
Which is the lesser evil?
Henrik Bærbak Christensen
27
But make it general!
This is a ’responsibility eroding’ way of doing it
In game.moveUnit:
if(winnerstrategy instanceof BattleWinner) {
((BattleWinner) winnerstrategy).winBattle(unit.getOwner(), this);
}
This is basically a parametric solution!
If ( variant == ZetaCiv ) { [increment counter] }
Thus you get the worst of both world
Henrik Bærbak Christensen
28
Others
Solution 1) / battle counter in Game +
A ’resetBattleCount()’ in GameImpl
– Invoked by the strategy after the 20th round
Bad idea!
– State in game => other parts may start using this
information
– But in one variant the count mysteriously resets after
20 rounds???
Henrik Bærbak Christensen
29
36.18: Alpha map = a test stub?
A wonderful discussion with TAs
– ”AlphaCiv map defined by particular customer, thus it
is not a test stub”
• It is in a production code folder
This is of course right, but...
– World layout optimized to support testing
• Supports ’evident test’ (units close for testing terrain)
• Is static (no randomness)
– Thus feeds indirect input, defined by test code
Henrik Bærbak Christensen
30
(so what is the answer?)
The answer (as often in this course) is
Sound and clear Argumention
On one hand Alpha Map exhibits
– (arguments in favour of considering it a test stub)
On the other hand
– (arguments in favour of considering it a test stub)
Therefore we conclude
–
Henrik Bærbak Christensen
31
© Copyright 2026 Paperzz