Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Toothpick - A fresh approach to DI (Including ...
Search
Daniel Molinero Reguera
April 11, 2017
Programming
1.2k
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Toothpick - A fresh approach to DI (Including Unit Testing)
Presented at Droidcon Boston 2017
Daniel Molinero Reguera
April 11, 2017
More Decks by Daniel Molinero Reguera
See All by Daniel Molinero Reguera
TP3 & KTP: Simple, fast, and boilerplate-free DI for Kotlin
dlemures
0
95
Toothpick - A fresh approach to DI - Short Version
dlemures
0
96
Toothpick Bad Practices 🙅 and Nice Tricks 👌
dlemures
0
130
Dart & Henson - Better Android Intents
dlemures
1
260
Toothpick - A fresh approach to DI
dlemures
0
160
Toothpick & Dependency Injection
dlemures
1
2.2k
Other Decks in Programming
See All in Programming
SODA - FACT BOOK(JP)
sodainc
1
40k
flutter_test のその先へ — Flutter アプリの LLM 機能に「評価」という品質保証を
kosukesaigusa
0
200
Enforcing Your Architecture with Unit Tests in the AI Era (Swift Connection X)
steliosf
PRO
1
150
Modernizing iOS Apps
seyfoyun
0
150
TanStack Vue Query と Pinia Colada から学ぶ非同期状態の型設計
aoshi
0
620
FactoryBotをやめればRSpecは速くなるのか?
yuta_onishi_97
0
1.6k
Optunaを作ったときにやりたかったこと、その後 (2026/10/16, Optuna Meetup #3)
iwiwi
4
1.5k
AI時代のFlutter品質設計 — アプリ品質を守るQuality Layers
omatty198
0
360
AIが生成したコードは読むべきか?抽象化設計とコードの品質保証 / abstraction-design-and-quality
minodriven
16
8.8k
[JA] Domain Modeling with Vanilla Rails: 「操作」から再考するRailsの設計論
yasaichi
4
1.8k
Getting Started with Vibe Coding
miccheng
0
190
Web Framework Benchmark Battle 2026, Any%
a_matsuda
3
3.1k
Featured
See All Featured
Tell your own story through comics
letsgokoyo
1
1.1k
The Power of CSS Pseudo Elements
geoffreycrofte
82
6.6k
Building an army of robots
kneath
307
47k
HDC tutorial
michielstock
2
1k
Building a A Zero-Code AI SEO Workflow
portentint
PRO
0
820
[Rails World 2026] Durable orchestration on Rails: from continuation to workflow
palkan
3
1.2k
Being A Developer After 40
akosma
PRO
92
590k
Why You Should Never Use an ORM
jnunemaker
PRO
61
10k
Ten Tips & Tricks for a 🌱 transition
stuffmc
1
280
GitHub's CSS Performance
jonrohan
1033
470k
Stop Working from a Prison Cell
hatefulcrawdad
274
21k
職位にかかわらず全員がリーダーシップを発揮するチーム作り / Building a team where everyone can demonstrate leadership regardless of position
madoxten
70
68k
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