Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Toothpick - A fresh approach to DI (Including ...
Search
Daniel Molinero Reguera
April 11, 2017
Programming
1
1.1k
Toothpick - A fresh approach to DI (Including Unit Testing)
Presented at Droidcon Boston 2017
Daniel Molinero Reguera
April 11, 2017
Tweet
Share
More Decks by Daniel Molinero Reguera
See All by Daniel Molinero Reguera
TP3 & KTP: Simple, fast, and boilerplate-free DI for Kotlin
dlemures
0
63
Toothpick - A fresh approach to DI - Short Version
dlemures
0
66
Toothpick Bad Practices 🙅 and Nice Tricks 👌
dlemures
0
100
Dart & Henson - Better Android Intents
dlemures
1
230
Toothpick - A fresh approach to DI
dlemures
0
130
Toothpick & Dependency Injection
dlemures
1
2k
Other Decks in Programming
See All in Programming
PipeCDのプラグイン化で目指すところ
warashi
1
280
Result型で“失敗”を型にするPHPコードの書き方
kajitack
5
880
XP, Testing and ninja testing
m_seki
3
250
GitHub Copilot and GitHub Codespaces Hands-on
ymd65536
2
150
Porting a visionOS App to Android XR
akkeylab
0
470
Python型ヒント完全ガイド 初心者でも分かる、現代的で実践的な使い方
mickey_kubo
1
120
Node-RED を(HTTP で)つなげる MCP サーバーを作ってみた
highu
0
120
なぜ「共通化」を考え、失敗を繰り返すのか
rinchoku
1
650
ニーリーにおけるプロダクトエンジニア
nealle
0
840
#QiitaBash MCPのセキュリティ
ryosukedtomita
1
1.3k
RailsGirls IZUMO スポンサーLT
16bitidol
0
190
Railsアプリケーションと パフォーマンスチューニング ー 秒間5万リクエストの モバイルオーダーシステムを支える事例 ー Rubyセミナー 大阪
falcon8823
5
1.1k
Featured
See All Featured
Java REST API Framework Comparison - PWX 2021
mraible
31
8.7k
Why Our Code Smells
bkeepers
PRO
336
57k
Fashionably flexible responsive web design (full day workshop)
malarkey
407
66k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
50
5.5k
The Art of Programming - Codeland 2020
erikaheidi
54
13k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
667
120k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
48
2.9k
The Cost Of JavaScript in 2023
addyosmani
51
8.5k
Scaling GitHub
holman
460
140k
Gamification - CAS2011
davidbonilla
81
5.4k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
18
970
Build your cross-platform service in a week with App Engine
jlugia
231
18k
Transcript
A FRESH APPROACH TO DI TOOTHPICK https://github.com/stephanenicolas/toothpick/
ABOUT US Senior Android Dev @ Groupon ~20 years of
Java coding OSS: Dart, TP, BoundBox, … STEPHANE NICOLAS DANIEL MOLINERO REGUERA Android Dev @ Groupon Turbulence Ninja OSS: Dart, TP. +stephane nicolas @D_Lemures
5IF"OESPJE5FBNJT)JSJOH jobs.groupon.com/careers/
THE TALK WHY DI ? WHY TOOTHPICK? TOOTHPICK FEATURES
SOME EXAMPLES UNIT TESTING CONCLUSION SCOPE MODULES & BINDINGS SCOPE TREE SCOPE SINGLETONS MVP & STATE PRESERVATION MULTIPLE ACTIVITIES FLOWS #DroidConBos | @D_Lemures | @GrouponEng
WHY DI ? #DroidConBos | @D_Lemures
WHY DI ? DECOUPLE #DroidConBos | @D_Lemures
WHY DI ? DECOUPLE USES #DroidConBos | @D_Lemures
WHY DI ? DECOUPLE REUSE USES #DroidConBos | @D_Lemures
WHY DI ? DECOUPLE REUSE USES USES USES #DroidConBos |
@D_Lemures
WHY DI ? DECOUPLE REUSE TEST USES USES USES #DroidConBos
| @D_Lemures
WHY DI ? DECOUPLE REUSE TEST USES USES USES MOCK
USES #DroidConBos | @D_Lemures
WHY TOOTHPICK? #DroidConBos | @D_Lemures
WHY TOOTHPICK? SIMPLER #DroidConBos | @D_Lemures
WHY TOOTHPICK? SIMPLER BETTER TEST SUPPORT #DroidConBos | @D_Lemures
WHY TOOTHPICK? SIMPLER BETTER TEST SUPPORT EVEN FASTER #DroidConBos |
@D_Lemures
TOOTHPICK FEATURES public class SmoothieMachine { @Inject IceMachine iceMachine;
public void doSmoothie() { iceMachine.makeIce(); } } @Singleton public class IceMachine { Foo foo; @Inject public IceMachine(Foo foo) { this.foo = foo; } #DroidConBos | @D_Lemures
TOOTHPICK FEATURES public class SmoothieMachine { @Inject IceMachine iceMachine;
public void doSmoothie() { iceMachine.makeIce(); } } @Singleton public class IceMachine { Foo foo; @Inject public IceMachine(Foo foo) { this.foo = foo; } JSR 330 annotations→nothing new here #DroidConBos | @D_Lemures
TOOTHPICK FEATURES SCOPE SCOPE #DroidConBos | @D_Lemures
TOOTHPICK FEATURES SCOPE SCOPE MAKE INJECTIONS #DroidConBos | @D_Lemures
TOOTHPICK FEATURES SCOPE SCOPE MAKE INJECTIONS public class MyApplication extends
Application { @Inject Machine machine; @Override protected void onCreate() { super.onCreate(); Scope appScope = Toothpick.openScope(this); appScope.installModules(…); Toothpick.inject(this, appScope); } } #DroidConBos | @D_Lemures
TOOTHPICK FEATURES SCOPE, MODULES & BINDINGS SCOPE #DroidConBos | @D_Lemures
TOOTHPICK FEATURES SCOPE, MODULES & BINDINGS SCOPE BINDINGS #DroidConBos |
@D_Lemures
TOOTHPICK FEATURES SCOPE, MODULES & BINDINGS SCOPE BINDINGS MODULES #DroidConBos
| @D_Lemures
TOOTHPICK FEATURES SCOPE, MODULES & BINDINGS SCOPE BINDINGS MODULES public
class MyApplication extends Application { @Inject Machine machine; @Override protected void onCreate() { super.onCreate(); Scope appScope = Toothpick.openScope(this); appScope.installModules(new Module() {{ bind(Machine.class).to(IceMachine.class); }}); Toothpick.inject(this, appScope); } } #DroidConBos | @D_Lemures
TOOTHPICK FEATURES APPLICATION SCOPE ACTIVITY 1 SCOPE SCOPE TREE #DroidConBos
| @D_Lemures
TOOTHPICK FEATURES APPLICATION SCOPE SCOPE TREE #DroidConBos | @D_Lemures
TOOTHPICK FEATURES APPLICATION SCOPE ACTIVITY 2 SCOPE SCOPE TREE #DroidConBos
| @D_Lemures
TOOTHPICK FEATURES APPLICATION SCOPE ACTIVITY 2 SCOPE SERVICE 1 SCOPE
SCOPE TREE #DroidConBos | @D_Lemures
TOOTHPICK FEATURES APPLICATION SCOPE ACTIVITY 2 SCOPE SERVICE 1 SCOPE
FRAGMENT 1 SCOPE SCOPE TREE #DroidConBos | @D_Lemures
TOOTHPICK FEATURES APPLICATION SCOPE ACTIVITY 2 SCOPE SERVICE 1 SCOPE
FRAGMENT 1 SCOPE FRAGMENT 2 SCOPE SCOPE TREE #DroidConBos | @D_Lemures
TOOTHPICK FEATURES APPLICATION SCOPE ACTIVITY 2 SCOPE SERVICE 1 SCOPE
FRAGMENT 3 SCOPE FRAGMENT 1 SCOPE FRAGMENT 2 SCOPE SCOPE TREE #DroidConBos | @D_Lemures
TOOTHPICK FEATURES public class LemonActivity extends Activity { @Inject Machine
machine; @Inject Context context; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Scope scope = Toothpick.openScopes(getApplication(), this); scope.installModules(new Module() {{ bind(Context.class).toInstance(this); }}); Toothpick.inject(this, scope); } } SCOPE TREE #DroidConBos | @D_Lemures
TOOTHPICK FEATURES public class LemonActivity extends Activity { @Inject Machine
machine; @Inject Context context; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Scope scope = Toothpick.openScopes(getApplication(), this); scope.installModules(new Module() {{ bind(Context.class).toInstance(this); }}); Toothpick.inject(this, scope); } } SCOPE TREE APPLICATION SCOPE ACTIVITY SCOPE #DroidConBos | @D_Lemures
TOOTHPICK FEATURES APPLICATION SCOPE ACTIVITY SCOPE SCOPE SINGLETONS #DroidConBos |
@D_Lemures
TOOTHPICK FEATURES APPLICATION SCOPE ACTIVITY SCOPE APP SINGLETONS SCOPE SINGLETONS
#DroidConBos | @D_Lemures
TOOTHPICK FEATURES APPLICATION SCOPE ACTIVITY SCOPE APP SINGLETONS ACTIVITY SINGLETONS
SCOPE SINGLETONS #DroidConBos | @D_Lemures
TOOTHPICK FEATURES public class Module extends Module { public Module()
{ bind(Machine.class).toInstance(new Ice Machine()); } } SCOPE SINGLETONS SINGLETONS CAN BE DEFINED IN MODULES #DroidConBos | @D_Lemures
TOOTHPICK FEATURES @Singleton public class IceMachine { } @ActivitySingleton public
class SmoothieMachine { } APPLICATION SCOPE ACTIVITY SCOPE SCOPE SINGLETONS OR USING ANNOTATIONS #DroidConBos | @D_Lemures
SOME EXAMPLES MVP & STATE PRESERVATION #DroidConBos | @D_Lemures
APPLICATION SCOPE MVP & STATE PRESERVATION ACTIVITY SCOPE SOME EXAMPLES
#DroidConBos | @D_Lemures
APPLICATION SCOPE MVP & STATE PRESERVATION ACTIVITY SCOPE SOME EXAMPLES
#DroidConBos | @D_Lemures
APPLICATION SCOPE PRESENTER SCOPE MVP & STATE PRESERVATION ACTIVITY SCOPE
SOME EXAMPLES #DroidConBos | @D_Lemures
PRESENTER INSTANCE APPLICATION SCOPE PRESENTER SCOPE MVP & STATE PRESERVATION
ACTIVITY SCOPE SOME EXAMPLES #DroidConBos | @D_Lemures
PRESENTER INSTANCE APPLICATION SCOPE PRESENTER SCOPE MVP & STATE PRESERVATION
SOME EXAMPLES #DroidConBos | @D_Lemures
PRESENTER INSTANCE APPLICATION SCOPE PRESENTER SCOPE MVP & STATE PRESERVATION
ACTIVITY SCOPE SOME EXAMPLES #DroidConBos | @D_Lemures
MVP & STATE PRESERVATION public class MyActivity extends Activity {
@Inject MyPresenter presenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Scope scope = openScopes(getApplication(), PresenterSingleton.class, this); Toothpick.inject(this, scope); } } SOME EXAMPLES #DroidConBos | @D_Lemures
@PresenterSingleton public class MyPresenter { String dealId; int quantity; }
PRESENTER SCOPE MVP & STATE PRESERVATION SOME EXAMPLES #DroidConBos | @D_Lemures
ACTIVITY 1 ACTIVITY 3 ACTIVITY 2 MULTI ACTIVITY FLOWS SOME
EXAMPLES #DroidConBos | @D_Lemures
ACTIVITY 1 ACTIVITY 3 ACTIVITY 2 MULTI ACTIVITY FLOWS Purchase
Flow SOME EXAMPLES #DroidConBos | @D_Lemures
ACTIVITY 1 ACTIVITY 3 ACTIVITY 2 MULTI ACTIVITY FLOWS Purchase
Flow SOME EXAMPLES #DroidConBos | @D_Lemures
ACTIVITY 1 ACTIVITY 3 ACTIVITY 2 MULTI ACTIVITY FLOWS SOME
EXAMPLES #DroidConBos | @D_Lemures
ACTIVITY 1 ACTIVITY 3 ACTIVITY 2 MULTI ACTIVITY FLOWS SOME
EXAMPLES #DroidConBos | @D_Lemures
ACTIVITY 1 ACTIVITY 3 ACTIVITY 2 MULTI ACTIVITY FLOWS SOME
EXAMPLES #DroidConBos | @D_Lemures
ACTIVITY 1 ACTIVITY 3 ACTIVITY 2 MULTI ACTIVITY FLOWS SOME
EXAMPLES #DroidConBos | @D_Lemures
APPLICATION SCOPE ACTIVITY 1 SCOPE FLOW SCOPE MULTI ACTIVITY FLOWS
SOME EXAMPLES #DroidConBos | @D_Lemures
APPLICATION SCOPE ACTIVITY 1 SCOPE FLOW SCOPE MULTI ACTIVITY FLOWS
SOME EXAMPLES #DroidConBos | @D_Lemures
APPLICATION SCOPE ACTIVITY 1 SCOPE FLOW SCOPE ACTIVITY 2 SCOPE
MULTI ACTIVITY FLOWS SOME EXAMPLES #DroidConBos | @D_Lemures
APPLICATION SCOPE ACTIVITY 1 SCOPE FLOW SCOPE ACTIVITY 3 SCOPE
ACTIVITY 2 SCOPE MULTI ACTIVITY FLOWS SOME EXAMPLES #DroidConBos | @D_Lemures
APPLICATION SCOPE FLOW SCOPE MULTI ACTIVITY FLOWS SOME EXAMPLES #DroidConBos
| @D_Lemures
APPLICATION SCOPE MULTI ACTIVITY FLOWS SOME EXAMPLES #DroidConBos | @D_Lemures
MVP & STATE PRESERVATION public class MyActivity extends Activity {
@Inject ShoppingCart shoppingCart; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Scope scope = openScopes(getApplication(), FlowSingleton.class, this); Toothpick.inject(this, scope); } } SOME EXAMPLES #DroidConBos | @D_Lemures
@FlowSingleton public class ShoppingCart { List<PurchaseItem> purchases… } FLOW SCOPE
MULTI ACTIVITY FLOWS SOME EXAMPLES #DroidConBos | @D_Lemures
UNIT TESTING WE TEST UNITS #DroidConBos | @D_Lemures
UNIT TESTING WE TEST UNITS MOCK USES WE MOCK DEPENDENCIES
#DroidConBos | @D_Lemures
UNIT TESTING public class SmoothieMachine { @Inject IceMachine iceMachine; @Inject
SyrupDispenser syrupDispenser; public void doSmoothie() { Smoothie smoothie = iceMachine.makeIce(); syrupDispenser.addSyrup(smoothie); return smoothie; } } WE WANT TO SIMULATE THE DEPENDENCIES #DroidConBos | @D_Lemures
UNIT TESTING public class TestSmoothieMachine extends EasyMockSupport { @Rule public
EasyMockRule easyMockRule = new EasyMockRule(this); @Mock IceMachine iceMachineMock; @Mock SyrupDispenser syrupDispenserMock; @Mock Smoothie smoothieMock; @Test public void doSmoothie_should_createSmoothie() { // GIVEN expect(iceMachineMock.makeIce()).andReturn(smoothieMock); syrupDispenserMock.addSyrup(smoothieMock); replayAll(); // WHEN Smoothie smoothie = smoothieMachine.doSmoothie(); // THEN assertThat(smoothie, sameInstance(smoothieMock)); verifyAll(); } } 1. CREATE MOCKS -> EASYMOCK #DroidConBos | @D_Lemures
UNIT TESTING public class TestSmoothieMachine extends EasyMockSupport { @Rule public
EasyMockRule easyMockRule = new EasyMockRule(this); @Rule public ToothPickRule toothPickRule = new ToothPickRule(this, “testScope”); @Mock IceMachine iceMachineMock; @Mock SyrupDispenser syrupDispenserMock; @Mock Smoothie smoothieMock; @Inject SmoothieMachine classUnderTest; @Test public void doSmoothie_should_createSmoothie() { // GIVEN expect(iceMachineMock.makeIce()).andReturn(smoothieMock); syrupDispenserMock.addSyrup(smoothieMock); replayAll(); // WHEN toothPickRule.inject(this); Smoothie smoothie = smoothieMachine.doSmoothie(); // THEN assertThat(smoothie, sameInstance(smoothieMock)); verifyAll(); } } 2. INJECT MOCKS -> TOOTHPICK #DroidConBos | @D_Lemures
CONCLUSION QUESTIONS ? COMMENTS ? #DroidConBos | @D_Lemures | @GrouponEng
CONCLUSION QUESTIONS ? COMMENTS ? #DroidConBos | @D_Lemures | @GrouponEng
A FRESH APPROACH TO DI TOOTHPICK https://github.com/stephanenicolas/toothpick/ +stephane nicolas @D_Lemures