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.2k
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
71
Toothpick - A fresh approach to DI - Short Version
dlemures
0
72
Toothpick Bad Practices 🙅 and Nice Tricks 👌
dlemures
0
110
Dart & Henson - Better Android Intents
dlemures
1
240
Toothpick - A fresh approach to DI
dlemures
0
140
Toothpick & Dependency Injection
dlemures
1
2.1k
Other Decks in Programming
See All in Programming
Implementation Patterns
denyspoltorak
0
140
Basic Architectures
denyspoltorak
0
140
はじめてのカスタムエージェント【GitHub Copilot Agent Mode編】
satoshi256kbyte
0
120
リリース時」テストから「デイリー実行」へ!開発マネージャが取り組んだ、レガシー自動テストのモダン化戦略
goataka
0
150
Flutter On-device AI로 완성하는 오프라인 앱, 박제창 @DevFest INCHEON 2025
itsmedreamwalker
1
160
実はマルチモーダルだった。ブラウザの組み込みAI🧠でWebの未来を感じてみよう #jsfes #gemini
n0bisuke2
3
1.3k
ゆくKotlin くるRust
exoego
1
170
Patterns of Patterns
denyspoltorak
0
390
複雑なUI設計への銀の弾丸 「オブジェクト指向UIデザイン」
teamlab
PRO
2
110
re:Invent 2025 のイケてるサービスを紹介する
maroon1st
0
150
生成AIを利用するだけでなく、投資できる組織へ
pospome
2
420
re:Invent 2025 トレンドからみる製品開発への AI Agent 活用
yoskoh
0
530
Featured
See All Featured
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
1.9k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
17k
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
34
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.5k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
4.1k
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
520
Abbi's Birthday
coloredviolet
0
4k
VelocityConf: Rendering Performance Case Studies
addyosmani
333
24k
How to Ace a Technical Interview
jacobian
281
24k
Leading Effective Engineering Teams in the AI Era
addyosmani
9
1.4k
Context Engineering - Making Every Token Count
addyosmani
9
560
BBQ
matthewcrist
89
9.9k
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