SlideShare une entreprise Scribd logo
1  sur  61
Télécharger pour lire hors ligne
Testable Android Apps
Fabio Collini
DroidCon Italy – Torino – April 2015 – @fabioCollini 2
Fabio Collini
@fabioCollini
linkedin.com/in/fabiocollini
Folder Organizer
cosenonjaviste.it
nana bianca
Freapp
instal.com
Rain tomorrow?
DroidCon Italy – Torino – April 2015 – @fabioCollini 3
Quick survey
Do you write automated tests?
DroidCon Italy – Torino – April 2015 – @fabioCollini 4
Return of Investment - ROI
Net profit
Investment
DroidCon Italy – Torino – April 2015 – @fabioCollini 5
Agenda
1. Legacy code
2. Dependency Injection
3. Mockito
4. Dagger
5. Dagger & Android
6. Model View Presenter
DroidCon Italy – Torino – April 2015 – @fabioCollini 6
TestableAndroidAppsDroidCon15
https://github.com/fabioCollini/
TestableAndroidAppsDroidCon15
DroidCon Italy - Torino - April 2015 - @fabioCollini
1Legacy code
DroidCon Italy – Torino – April 2015 – @fabioCollini 8
Legacy code
Edit and pray
Vs
Cover and modify
Legacy code is code
without unit tests
DroidCon Italy – Torino – April 2015 – @fabioCollini 9
Instrumentation tests
run on a device (real or emulated)
high code coverage
Vs
JVM tests
fast
low code coverage
DroidCon Italy – Torino – April 2015 – @fabioCollini 10
Espresso
public class PostListActivityTest {
//see https://gist.github.com/JakeWharton/1c2f2cadab2ddd97f9fb

@Rule

public ActivityRule<PostListActivity> rule =
new ActivityRule<>(PostListActivity.class);



}
@Test public void showListActivity() {

onView(withText("???"))
.check(matches(isDisplayed()));

}

@Test public void showErrorLayoutOnServerError() {

//???

onView(withId(R.id.error_layout))
.check(matches(isDisplayed()));
}
DroidCon Italy – Torino – April 2015 – @fabioCollini 11
Legacy code dilemma
When we change code,
we should have tests in place.
To put tests in place,
we often have to change code.
Michael Feathers
DroidCon Italy – Torino – April 2015 – @fabioCollini 12
TestablePostListActivity
public class TestablePostListActivity
extends PostListActivity {



public static Observable<List<Post>> result;



@Override
protected Observable<List<Post>> createListObservable() {

return result;

}

}
DroidCon Italy – Torino – April 2015 – @fabioCollini 13
PostListActivityTest
public class PostListActivityTest {


@Rule public ActivityRule<TestablePostListActivity> rule =
new ActivityRule<>(
TestablePostListActivity.class,
false
);



@Test public void showListActivity() {

TestablePostListActivity.result = Observable.just(

createPost(1), createPost(2), createPost(3)

).toList();



rule.launchActivity();



onView(withText("title 1”))
.check(matches(isDisplayed()));

}
DroidCon Italy – Torino – April 2015 – @fabioCollini 14
PostListActivityTest
@Test public void checkErrorLayoutDisplayed() {

TestablePostListActivity.result =
Observable.error(new IOException());



rule.launchActivity();



onView(withId(R.id.error_layout))
.check(matches(isDisplayed()));

}
DroidCon Italy – Torino – April 2015 – @fabioCollini 15
Legacy code
Not the perfect solution
First step to increase coverage
Then modify and refactor
DroidCon Italy - Torino - April 2015 - @fabioCollini
2Dependency Injection
DroidCon Italy – Torino – April 2015 – @fabioCollini 17
PostBatch
public void execute() {

PostResponse postResponse = createService().listPosts();

EmailSender emailSender = new EmailSender();



List<Post> posts = postResponse.getPosts();

for (Post post : posts) {

emailSender.sendEmail(post);

}

}



private static WordPressService createService() {

//...

}
DroidCon Italy – Torino – April 2015 – @fabioCollini 18
PostBatch
WordPressService
EmailSender
Class under test
Collaborator
Collaborator
DroidCon Italy – Torino – April 2015 – @fabioCollini 19
PostBatchTest
public class PostBatchTest {



private PostBatch postBatch = new PostBatch();



@Test

public void testExecute() {

postBatch.execute();

//???

}

}
DroidCon Italy – Torino – April 2015 – @fabioCollini 20
Inversion Of Control
private WordPressService wordPressService;



private EmailSender emailSender;



public PostBatch(WordPressService wordPressService,
EmailSender emailSender) {

this.wordPressService = wordPressService;

this.emailSender = emailSender;

}



public void execute() {

PostResponse postResponse = wordPressService.listPosts();

List<Post> posts = postResponse.getPosts();

for (Post post : posts) {

emailSender.sendEmail(post);

}

}
DroidCon Italy – Torino – April 2015 – @fabioCollini 21
Dependency Injection
public class Main {



public static void main(String[] args) {

new PostBatch(
createService(), new EmailSender()
).execute();

}



private static WordPressService createService() {

//...

}

}
DroidCon Italy – Torino – April 2015 – @fabioCollini 22
WordPressServiceStub
public class WordPressServiceStub
implements WordPressService {



private PostResponse postResponse;



public WordPressServiceStub(PostResponse postResponse) {

this.postResponse = postResponse;

}



@Override public PostResponse listPosts() {

return postResponse;

}

}
DroidCon Italy – Torino – April 2015 – @fabioCollini 23
EmailSenderSpy
public class EmailSenderSpy extends EmailSender {



private int emailCount;



@Override public void sendEmail(Post p) {

emailCount++;

}



public int getEmailCount() {

return emailCount;

}

}
DroidCon Italy – Torino – April 2015 – @fabioCollini 24
PostBatch
WordPressService
EmailSender
Stub
Spy
DroidCon Italy – Torino – April 2015 – @fabioCollini 25
Test doubles
private PostBatch postBatch;



private EmailSenderSpy emailSenderSpy;



private WordPressServiceStub serviceStub;
@Test

public void testExecute() {

postBatch.execute();

assertEquals(3, emailSenderSpy.getEmailCount());

}
@Before public void init() {

emailSenderSpy = new EmailSenderSpy();

serviceStub = new WordPressServiceStub(
new PostResponse(new Post(), new Post(), new Post())
);

postBatch = new PostBatch(serviceStub, emailSenderSpy);

}

DroidCon Italy - Torino - April 2015 - @fabioCollini
3Mockito
DroidCon Italy – Torino – April 2015 – @fabioCollini 27
Mockito
private WordPressService service;

private EmailSender emailSender;

private PostBatch postBatch;

@Before public void init() {

emailSender = Mockito.mock(EmailSender.class);

service = Mockito.mock(WordPressService.class);

postBatch = new PostBatch(service, emailSender);

}
@Test public void testExecute() {

when(service.listPosts()).thenReturn(
new PostResponse(new Post(), new Post(), new Post()));



postBatch.execute();



verify(emailSender, times(3)).sendEmail(any(Post.class));

}
ArrangeActAssert
DroidCon Italy – Torino – April 2015 – @fabioCollini 28
@InjectMocks
@RunWith(MockitoJUnitRunner.class)

public class PostBatchTest {



@Mock WordPressService service;



@Mock EmailSender sender;



@InjectMocks PostBatch postBatch;



@Test

public void testExecute() {

when(service.listPosts()).thenReturn(
new PostResponse(new Post(), new Post(), new Post()));



postBatch.execute();



verify(sender, times(3)).sendEmail(any(Post.class));

}

}
DroidCon Italy - Torino - April 2015 - @fabioCollini
4Dagger
DroidCon Italy – Torino – April 2015 – @fabioCollini 30
Dagger
A fast dependency injector for Android and Java
v1 developed at Square
https://github.com/square/dagger
v2 developed at Google
https://github.com/google/dagger
Configuration using annotations and Java classes
Based on annotation processing (no reflection)
DroidCon Italy – Torino – April 2015 – @fabioCollini 31
Module
@Module

public class MainModule {


@Provides @Singleton EmailSender provideEmailSender() {

return new EmailSender();

}



@Provides @Singleton WordPressService provideService() {

//...

}



@Provides PostBatch providePostsBatch(
WordPressService wordPressService,
EmailSender emailSender) {

return new PostBatch(wordPressService, emailSender);

}

}
DroidCon Italy – Torino – April 2015 – @fabioCollini 32
PostBatch
WordPressService
EmailSender
Component
Main
DroidCon Italy – Torino – April 2015 – @fabioCollini 33
Component
@Singleton

@Component(modules = MainModule.class)

public interface MainComponent {

PostBatch getBatch();

}
public class Main {

public static void main(String[] args) {

MainComponent component = DaggerMainComponent.create();
PostBatch batch = component.getBatch();

batch.execute();

}

}
DroidCon Italy – Torino – April 2015 – @fabioCollini 34
Inject annotation
public class PostBatch {

private WordPressService wordPressService;

private EmailSender emailSender;



@Inject public PostBatch(
WordPressService wordPressService,
EmailSender emailSender) {

this.wordPressService = wordPressService;

this.emailSender = emailSender;

}
}
public class PostBatch {

@Inject WordPressService wordPressService;

@Inject EmailSender emailSender;

@Inject public PostBatch() {

}

}
DroidCon Italy - Torino - April 2015 - @fabioCollini
5Dagger & Android
DroidCon Italy – Torino – April 2015 – @fabioCollini 36
PostListActivity
WordPressService
ShareActivity
ShareExecutor
DroidCon Italy – Torino – April 2015 – @fabioCollini 37
ShareExecutor
public class ShareExecutor {

private Context context;


public ShareExecutor(Context context) {

this.context = context;

}



public void startSendActivity(String title, String body) {

Intent intent = new Intent();

intent.setAction(Intent.ACTION_SEND);

intent.putExtra(Intent.EXTRA_TITLE, title);

intent.putExtra(Intent.EXTRA_TEXT, body);

intent.setType("text/plain");

Intent chooserIntent = Intent.createChooser(intent,
context.getResources().getText(R.string.share));

chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(chooserIntent);
}

}
DroidCon Italy – Torino – April 2015 – @fabioCollini 38
ApplicationModule
@Module public class ApplicationModule {

private Application application;

public ApplicationModule(Application application) {

this.application = application;

}


@Provides @Singleton WordPressService providesService() {

//...

}

@Provides @Singleton ShareExecutor shareExecutor() {

return new ShareExecutor(application);

}

}
DroidCon Italy – Torino – April 2015 – @fabioCollini 39
ApplicationComponent
@Singleton
@Component(modules = ApplicationModule.class)

public interface ApplicationComponent {


void inject(PostListActivity activity);

void inject(ShareActivity activity);
}
DroidCon Italy – Torino – April 2015 – @fabioCollini 40
Component
PostListActivity
Application
ShareActivity
ShareExecutorWordPressService
DroidCon Italy – Torino – April 2015 – @fabioCollini 41
Application
public class CnjApplication extends Application {



private ApplicationComponent component;



@Override public void onCreate() {

super.onCreate();

component = DaggerApplicationComponent.builder()

.applicationModule(new ApplicationModule(this))

.build();

}



public ApplicationComponent getComponent() {

return component;

}



public void setComponent(ApplicationComponent c) {

this.component = c;

}

}
DroidCon Italy – Torino – April 2015 – @fabioCollini 42
PostListActivity
public class PostListActivity extends ActionBarActivity {

//...

@Inject WordPressService wordPressService;



@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

CnjApplication app =
(CnjApplication) getApplicationContext();
ApplicationComponent component = app.getComponent();

component.inject(this);



//...

}

//...

}
DroidCon Italy – Torino – April 2015 – @fabioCollini 43
Component
PostListActivity
Application
ShareExecutorWordPressService
TestComponent
MockMock
Test
DroidCon Italy – Torino – April 2015 – @fabioCollini 44
TestModule
@Module

public class TestModule {

@Provides @Singleton
ShareExecutor provideShareExecutor() {

return Mockito.mock(ShareExecutor.class);

}

@Provides @Singleton
WordPressService providesWordPressService() {

return Mockito.mock(WordPressService.class);

}

}
DroidCon Italy – Torino – April 2015 – @fabioCollini 45
TestComponent
@Singleton

@Component(modules = TestModule.class)

public interface TestComponent
extends ApplicationComponent {

void inject(PostListActivityTest test);



void inject(ShareActivityTest test);

}
DroidCon Italy – Torino – April 2015 – @fabioCollini 46
PostListActivityTest
public class PostListActivityTest {



@Inject WordPressService wordPressService;



@Rule public ActivityRule<PostListActivity> rule =
new ActivityRule<>(PostListActivity.class, false);

@Before public void setUp() {

TestComponent component =
DaggerTestComponent.create();

CnjApplication application =
(CnjApplication) rule.getApplication();

application.setComponent(component);

component.inject(this);

}
//...
DroidCon Italy – Torino – April 2015 – @fabioCollini 47
PostListActivityTest
@Test
public void showListActivity() {

when(wordPressService.listPosts()).thenReturn(
Observable.just(new PostResponse(createPost(1),
createPost(2), createPost(3))));



rule.launchActivity();



onView(withText("title 1”))
.check(matches(isDisplayed()));

}
DroidCon Italy – Torino – April 2015 – @fabioCollini 48
PostListActivityTest


@Test
public void showErrorLayoutOnServerError() {

when(wordPressService.listPosts()).thenReturn(
Observable.error(new IOException("error!")));



rule.launchActivity();



onView(withId(R.id.error_layout))
.check(matches(isDisplayed()));

}
DroidCon Italy - Torino - April 2015 - @fabioCollini
6Model View Presenter
DroidCon Italy – Torino – April 2015 – @fabioCollini 50
Model View Presenter
View
Presenter
Model
DroidCon Italy – Torino – April 2015 – @fabioCollini 51
View Presenter RetrofitService
onClick
update
update(model)
Model
View Presenter RetrofitServiceModel
request
response
DroidCon Italy – Torino – April 2015 – @fabioCollini 52
View Presenter MockService
perform(click())
update
update(model)
Model
request
response
EspressoTest
View Presenter MockServiceModelEspressoTest
onView
verify
when().thenReturn()
onClick
DroidCon Italy – Torino – April 2015 – @fabioCollini 53
MockView Presenter MockService
onClick
update
update(model)
Model
request
response
JVM Test
MockView Presenter MockServiceModelJVM Test
verify
verify
assert
when().thenReturn()
DroidCon Italy – Torino – April 2015 – @fabioCollini 54
View Presenter
init
update(model)
ModelEspressoTest
View Presenter ModelEspressoTest
onView
create
DroidCon Italy – Torino – April 2015 – @fabioCollini 55
Android Model View Presenter
Activity (or Fragment) is the View
All the business logic is in the Presenter
Presenter is managed using Dagger
Model is the Activity (or Fragment) state
Presenter is retained on configuration change
DroidCon Italy – Torino – April 2015 – @fabioCollini 56
PostListPresenter JVM Test
@RunWith(MockitoJUnitRunner.class)

public class PostListPresenterTest {



@Mock WordPressService wordPressService;



@Mock PostListActivity view;



private PostListPresenter postListPresenter;



@Before public void setUp() {
SchedulerManager schedulerManager =
new SchedulerManager(
Schedulers.immediate(), Schedulers.immediate());


postListPresenter = new PostListPresenter(
wordPressService, schedulerManager
);

}

//...
DroidCon Italy – Torino – April 2015 – @fabioCollini 57
PostListPresenter JVM Test
@Test

public void loadingPosts() {
when(wordPressService.listPosts()).thenReturn(
Observable.just(new PostResponse(new Post(),
new Post(), new Post())));



PostListModel model = new PostListModel();

postListPresenter.setModel(model);

postListPresenter.resume(view);



assertEquals(3, model.getItems().size());

}
DroidCon Italy – Torino – April 2015 – @fabioCollini 58
PostListPresenter JVM Test
@Test

public void clickOnItem() {

PostListModel model = new PostListModel();

model.setItems(Arrays.asList(
createPost(1), createPost(2), createPost(3)));

postListPresenter.setModel(model);

postListPresenter.resume(view);



postListPresenter.onItemClick(1);



verify(view).startShareActivity(
eq("title 2"), eq("name 2 last name 2nexcerpt 2"));

}
DroidCon Italy – Torino – April 2015 – @fabioCollini 59
SharePresenter JVM Test
@RunWith(MockitoJUnitRunner.class)

public class SharePresenterTest {



@Mock ShareExecutor shareExecutor;



@Mock ShareActivity view;



@InjectMocks SharePresenter sharePresenter;



@Test public void testValidationOk() {
ShareModel model = new ShareModel();

sharePresenter.init(view, model);



sharePresenter.share("title", "body");



verify(shareExecutor)
.startSendActivity(eq("title"), eq("body"));

}

}
DroidCon Italy – Torino – April 2015 – @fabioCollini 60
TL;DR
Dagger
Mockito
Espresso UI tests
JVM Presenter tests
DroidCon Italy – Torino – April 2015 – @fabioCollini 61
Thanks for your attention!
Questions?
github.com/fabioCollini/
TestableAndroidAppsDroidCon15
github.com/google/dagger
mockito.org
cosenonjaviste.it/libri

Contenu connexe

Tendances

Guice tutorial
Guice tutorialGuice tutorial
Guice tutorialAnh Quân
 
Codeu+git+flow+presentation
Codeu+git+flow+presentationCodeu+git+flow+presentation
Codeu+git+flow+presentationLars Kruse
 
My way to clean android (EN) - Android day salamanca edition
My way to clean android (EN) - Android day salamanca editionMy way to clean android (EN) - Android day salamanca edition
My way to clean android (EN) - Android day salamanca editionChristian Panadero
 
My way to clean android v2 English DroidCon Spain
My way to clean android v2 English DroidCon SpainMy way to clean android v2 English DroidCon Spain
My way to clean android v2 English DroidCon SpainChristian Panadero
 
My way to clean android - Android day salamanca edition
My way to clean android - Android day salamanca editionMy way to clean android - Android day salamanca edition
My way to clean android - Android day salamanca editionChristian Panadero
 
Android and NFC / NDEF (with Kotlin)
Android and NFC / NDEF (with Kotlin)Android and NFC / NDEF (with Kotlin)
Android and NFC / NDEF (with Kotlin)Andreas Jakl
 
GOTO - The Ultimate Android Lock Screen
GOTO - The Ultimate Android Lock ScreenGOTO - The Ultimate Android Lock Screen
GOTO - The Ultimate Android Lock ScreenInnoWeb Tech, LLC
 

Tendances (8)

Guice tutorial
Guice tutorialGuice tutorial
Guice tutorial
 
Codeu+git+flow+presentation
Codeu+git+flow+presentationCodeu+git+flow+presentation
Codeu+git+flow+presentation
 
My way to clean android V2
My way to clean android V2My way to clean android V2
My way to clean android V2
 
My way to clean android (EN) - Android day salamanca edition
My way to clean android (EN) - Android day salamanca editionMy way to clean android (EN) - Android day salamanca edition
My way to clean android (EN) - Android day salamanca edition
 
My way to clean android v2 English DroidCon Spain
My way to clean android v2 English DroidCon SpainMy way to clean android v2 English DroidCon Spain
My way to clean android v2 English DroidCon Spain
 
My way to clean android - Android day salamanca edition
My way to clean android - Android day salamanca editionMy way to clean android - Android day salamanca edition
My way to clean android - Android day salamanca edition
 
Android and NFC / NDEF (with Kotlin)
Android and NFC / NDEF (with Kotlin)Android and NFC / NDEF (with Kotlin)
Android and NFC / NDEF (with Kotlin)
 
GOTO - The Ultimate Android Lock Screen
GOTO - The Ultimate Android Lock ScreenGOTO - The Ultimate Android Lock Screen
GOTO - The Ultimate Android Lock Screen
 

En vedette

Introduction to Retrofit and RxJava
Introduction to Retrofit and RxJavaIntroduction to Retrofit and RxJava
Introduction to Retrofit and RxJavaFabio Collini
 
Android Data Binding in action using MVVM pattern - droidconUK
Android Data Binding in action using MVVM pattern - droidconUKAndroid Data Binding in action using MVVM pattern - droidconUK
Android Data Binding in action using MVVM pattern - droidconUKFabio Collini
 
Data Binding in Action using MVVM pattern
Data Binding in Action using MVVM patternData Binding in Action using MVVM pattern
Data Binding in Action using MVVM patternFabio Collini
 
Android Widget @ whymca 2011
Android Widget @ whymca 2011Android Widget @ whymca 2011
Android Widget @ whymca 2011Fabio Collini
 
Clean android code - Droidcon Italiy 2014
Clean android code - Droidcon Italiy 2014Clean android code - Droidcon Italiy 2014
Clean android code - Droidcon Italiy 2014Fabio Collini
 
Librerie su Android: come non reinventare la ruota @ whymca 2012
Librerie su Android: come non reinventare la ruota @ whymca 2012 Librerie su Android: come non reinventare la ruota @ whymca 2012
Librerie su Android: come non reinventare la ruota @ whymca 2012 Fabio Collini
 
Model-View-ViewModel and RxJava
Model-View-ViewModel and RxJavaModel-View-ViewModel and RxJava
Model-View-ViewModel and RxJavaFlorina Muntenescu
 
Windows 7 For Geeks
Windows 7 For GeeksWindows 7 For Geeks
Windows 7 For GeeksAdil Mughal
 
Community Contribution Experience
Community Contribution ExperienceCommunity Contribution Experience
Community Contribution ExperienceAdil Mughal
 
What's New in Visual Studio 2010
What's New in Visual Studio 2010What's New in Visual Studio 2010
What's New in Visual Studio 2010Adil Mughal
 
DevNext - Web Programming Concepts Using Asp Net
DevNext - Web Programming Concepts Using Asp NetDevNext - Web Programming Concepts Using Asp Net
DevNext - Web Programming Concepts Using Asp NetAdil Mughal
 
Code Sharing Between Windows Phone/Store Apps
Code Sharing Between Windows Phone/Store AppsCode Sharing Between Windows Phone/Store Apps
Code Sharing Between Windows Phone/Store AppsAdil Mughal
 
Write cleaner, maintainable, and testable code in Android with MVVM
Write cleaner, maintainable, and testable code in Android with MVVMWrite cleaner, maintainable, and testable code in Android with MVVM
Write cleaner, maintainable, and testable code in Android with MVVMAdil Mughal
 
Web Development using ASP.NET MVC at HEC
Web Development using ASP.NET MVC at HECWeb Development using ASP.NET MVC at HEC
Web Development using ASP.NET MVC at HECAdil Mughal
 
MVVM with DataBinding on android
MVVM with DataBinding on androidMVVM with DataBinding on android
MVVM with DataBinding on androidRodrigo Bressan
 
Mockito, Robobinding
Mockito, RobobindingMockito, Robobinding
Mockito, RobobindingKyungHo Jung
 
Rx Creating Operators, observeOn, subscribeOn
Rx Creating Operators, observeOn, subscribeOnRx Creating Operators, observeOn, subscribeOn
Rx Creating Operators, observeOn, subscribeOnKyungHo Jung
 
May 05 test_code_states
May 05 test_code_statesMay 05 test_code_states
May 05 test_code_statesKyungHo Jung
 
Kotlin 사용기
Kotlin 사용기Kotlin 사용기
Kotlin 사용기KyungHo Jung
 

En vedette (20)

Introduction to Retrofit and RxJava
Introduction to Retrofit and RxJavaIntroduction to Retrofit and RxJava
Introduction to Retrofit and RxJava
 
Android Data Binding in action using MVVM pattern - droidconUK
Android Data Binding in action using MVVM pattern - droidconUKAndroid Data Binding in action using MVVM pattern - droidconUK
Android Data Binding in action using MVVM pattern - droidconUK
 
Data Binding in Action using MVVM pattern
Data Binding in Action using MVVM patternData Binding in Action using MVVM pattern
Data Binding in Action using MVVM pattern
 
Android Widget @ whymca 2011
Android Widget @ whymca 2011Android Widget @ whymca 2011
Android Widget @ whymca 2011
 
Clean android code - Droidcon Italiy 2014
Clean android code - Droidcon Italiy 2014Clean android code - Droidcon Italiy 2014
Clean android code - Droidcon Italiy 2014
 
Librerie su Android: come non reinventare la ruota @ whymca 2012
Librerie su Android: come non reinventare la ruota @ whymca 2012 Librerie su Android: come non reinventare la ruota @ whymca 2012
Librerie su Android: come non reinventare la ruota @ whymca 2012
 
Model-View-ViewModel and RxJava
Model-View-ViewModel and RxJavaModel-View-ViewModel and RxJava
Model-View-ViewModel and RxJava
 
Windows 7 For Geeks
Windows 7 For GeeksWindows 7 For Geeks
Windows 7 For Geeks
 
Community Contribution Experience
Community Contribution ExperienceCommunity Contribution Experience
Community Contribution Experience
 
What's New in Visual Studio 2010
What's New in Visual Studio 2010What's New in Visual Studio 2010
What's New in Visual Studio 2010
 
DevNext - Web Programming Concepts Using Asp Net
DevNext - Web Programming Concepts Using Asp NetDevNext - Web Programming Concepts Using Asp Net
DevNext - Web Programming Concepts Using Asp Net
 
Code Sharing Between Windows Phone/Store Apps
Code Sharing Between Windows Phone/Store AppsCode Sharing Between Windows Phone/Store Apps
Code Sharing Between Windows Phone/Store Apps
 
Write cleaner, maintainable, and testable code in Android with MVVM
Write cleaner, maintainable, and testable code in Android with MVVMWrite cleaner, maintainable, and testable code in Android with MVVM
Write cleaner, maintainable, and testable code in Android with MVVM
 
Web Development using ASP.NET MVC at HEC
Web Development using ASP.NET MVC at HECWeb Development using ASP.NET MVC at HEC
Web Development using ASP.NET MVC at HEC
 
MVVM with DataBinding on android
MVVM with DataBinding on androidMVVM with DataBinding on android
MVVM with DataBinding on android
 
Mockito, Robobinding
Mockito, RobobindingMockito, Robobinding
Mockito, Robobinding
 
Rx Creating Operators, observeOn, subscribeOn
Rx Creating Operators, observeOn, subscribeOnRx Creating Operators, observeOn, subscribeOn
Rx Creating Operators, observeOn, subscribeOn
 
May 05 test_code_states
May 05 test_code_statesMay 05 test_code_states
May 05 test_code_states
 
Kotlin 사용기
Kotlin 사용기Kotlin 사용기
Kotlin 사용기
 
Android MVVM TDD
Android MVVM TDDAndroid MVVM TDD
Android MVVM TDD
 

Similaire à Testable Android Apps DroidCon Italy 2015

The real beginner's guide to android testing
The real beginner's guide to android testingThe real beginner's guide to android testing
The real beginner's guide to android testingEric (Trung Dung) Nguyen
 
Writing Kotlin Multiplatform libraries that your iOS teammates are gonna love
Writing Kotlin Multiplatform libraries that your iOS teammates are gonna loveWriting Kotlin Multiplatform libraries that your iOS teammates are gonna love
Writing Kotlin Multiplatform libraries that your iOS teammates are gonna loveAndré Oriani
 
Going native with less coupling: Dependency Injection in C++
Going native with less coupling: Dependency Injection in C++Going native with less coupling: Dependency Injection in C++
Going native with less coupling: Dependency Injection in C++Daniele Pallastrelli
 
Unit Testing Using Mockito in Android (1).pdf
Unit Testing Using Mockito in Android (1).pdfUnit Testing Using Mockito in Android (1).pdf
Unit Testing Using Mockito in Android (1).pdfKaty Slemon
 
Встреча Google Post IO ( Владимир Иванов, Катерина Заворотченко и Сергей Комлач)
Встреча Google Post IO ( Владимир Иванов, Катерина Заворотченко и Сергей Комлач)Встреча Google Post IO ( Владимир Иванов, Катерина Заворотченко и Сергей Комлач)
Встреча Google Post IO ( Владимир Иванов, Катерина Заворотченко и Сергей Комлач)Alina Vilk
 
Improve your Android-Fu with Kotlin
Improve your Android-Fu with KotlinImprove your Android-Fu with Kotlin
Improve your Android-Fu with KotlinNicolas Fränkel
 
Mastering UI automation at Scale: Key Lessons and Best Practices (By Fernando...
Mastering UI automation at Scale: Key Lessons and Best Practices (By Fernando...Mastering UI automation at Scale: Key Lessons and Best Practices (By Fernando...
Mastering UI automation at Scale: Key Lessons and Best Practices (By Fernando...Applitools
 
Palestra "Ionic Framework 2 - O que vem por aí?" TDC 2016
Palestra "Ionic Framework 2 - O que vem por aí?" TDC 2016Palestra "Ionic Framework 2 - O que vem por aí?" TDC 2016
Palestra "Ionic Framework 2 - O que vem por aí?" TDC 2016Tatiane Aguirres Nogueira
 
#jjug_ccc #ccc_gh5 What's new in Spring Framework 4.3 / Boot 1.4 + Pivotal's ...
#jjug_ccc #ccc_gh5 What's new in Spring Framework 4.3 / Boot 1.4 + Pivotal's ...#jjug_ccc #ccc_gh5 What's new in Spring Framework 4.3 / Boot 1.4 + Pivotal's ...
#jjug_ccc #ccc_gh5 What's new in Spring Framework 4.3 / Boot 1.4 + Pivotal's ...Toshiaki Maki
 
SOS UiComponents
SOS UiComponentsSOS UiComponents
SOS UiComponentsvinaikopp
 
Using Dagger in a Clean Architecture project
Using Dagger in a Clean Architecture projectUsing Dagger in a Clean Architecture project
Using Dagger in a Clean Architecture projectFabio Collini
 
Microsoft ♥ Open Source
Microsoft ♥ Open SourceMicrosoft ♥ Open Source
Microsoft ♥ Open SourceRicardo Peres
 
C# Tutorial MSM_Murach chapter-15-slides
C# Tutorial MSM_Murach chapter-15-slidesC# Tutorial MSM_Murach chapter-15-slides
C# Tutorial MSM_Murach chapter-15-slidesSami Mut
 
Avoiding and dealing with conflicting updates in Oak
Avoiding and dealing with conflicting updates in OakAvoiding and dealing with conflicting updates in Oak
Avoiding and dealing with conflicting updates in Oakmichid
 
Testing Android apps based on Dagger and RxJava
Testing Android apps based on Dagger and RxJavaTesting Android apps based on Dagger and RxJava
Testing Android apps based on Dagger and RxJavaFabio Collini
 
Moderne App-Architektur mit Dagger2 und RxJava
Moderne App-Architektur mit Dagger2 und RxJavaModerne App-Architektur mit Dagger2 und RxJava
Moderne App-Architektur mit Dagger2 und RxJavainovex GmbH
 
Анастасия Войтова: Здоровая психологическая атмосфера в жизни разработчика, ...
Анастасия Войтова:  Здоровая психологическая атмосфера в жизни разработчика, ...Анастасия Войтова:  Здоровая психологическая атмосфера в жизни разработчика, ...
Анастасия Войтова: Здоровая психологическая атмосфера в жизни разработчика, ...Fwdays
 
A realtime infrastructure for Android apps: Firebase may be what you need..an...
A realtime infrastructure for Android apps: Firebase may be what you need..an...A realtime infrastructure for Android apps: Firebase may be what you need..an...
A realtime infrastructure for Android apps: Firebase may be what you need..an...Alessandro Martellucci
 

Similaire à Testable Android Apps DroidCon Italy 2015 (20)

The real beginner's guide to android testing
The real beginner's guide to android testingThe real beginner's guide to android testing
The real beginner's guide to android testing
 
Writing Kotlin Multiplatform libraries that your iOS teammates are gonna love
Writing Kotlin Multiplatform libraries that your iOS teammates are gonna loveWriting Kotlin Multiplatform libraries that your iOS teammates are gonna love
Writing Kotlin Multiplatform libraries that your iOS teammates are gonna love
 
Going native with less coupling: Dependency Injection in C++
Going native with less coupling: Dependency Injection in C++Going native with less coupling: Dependency Injection in C++
Going native with less coupling: Dependency Injection in C++
 
Unit Testing Using Mockito in Android (1).pdf
Unit Testing Using Mockito in Android (1).pdfUnit Testing Using Mockito in Android (1).pdf
Unit Testing Using Mockito in Android (1).pdf
 
VR Workshop #2
VR Workshop #2VR Workshop #2
VR Workshop #2
 
Встреча Google Post IO ( Владимир Иванов, Катерина Заворотченко и Сергей Комлач)
Встреча Google Post IO ( Владимир Иванов, Катерина Заворотченко и Сергей Комлач)Встреча Google Post IO ( Владимир Иванов, Катерина Заворотченко и Сергей Комлач)
Встреча Google Post IO ( Владимир Иванов, Катерина Заворотченко и Сергей Комлач)
 
Improve your Android-Fu with Kotlin
Improve your Android-Fu with KotlinImprove your Android-Fu with Kotlin
Improve your Android-Fu with Kotlin
 
Mastering UI automation at Scale: Key Lessons and Best Practices (By Fernando...
Mastering UI automation at Scale: Key Lessons and Best Practices (By Fernando...Mastering UI automation at Scale: Key Lessons and Best Practices (By Fernando...
Mastering UI automation at Scale: Key Lessons and Best Practices (By Fernando...
 
Palestra "Ionic Framework 2 - O que vem por aí?" TDC 2016
Palestra "Ionic Framework 2 - O que vem por aí?" TDC 2016Palestra "Ionic Framework 2 - O que vem por aí?" TDC 2016
Palestra "Ionic Framework 2 - O que vem por aí?" TDC 2016
 
#jjug_ccc #ccc_gh5 What's new in Spring Framework 4.3 / Boot 1.4 + Pivotal's ...
#jjug_ccc #ccc_gh5 What's new in Spring Framework 4.3 / Boot 1.4 + Pivotal's ...#jjug_ccc #ccc_gh5 What's new in Spring Framework 4.3 / Boot 1.4 + Pivotal's ...
#jjug_ccc #ccc_gh5 What's new in Spring Framework 4.3 / Boot 1.4 + Pivotal's ...
 
SOS UiComponents
SOS UiComponentsSOS UiComponents
SOS UiComponents
 
Using Dagger in a Clean Architecture project
Using Dagger in a Clean Architecture projectUsing Dagger in a Clean Architecture project
Using Dagger in a Clean Architecture project
 
Microsoft ♥ Open Source
Microsoft ♥ Open SourceMicrosoft ♥ Open Source
Microsoft ♥ Open Source
 
C# Tutorial MSM_Murach chapter-15-slides
C# Tutorial MSM_Murach chapter-15-slidesC# Tutorial MSM_Murach chapter-15-slides
C# Tutorial MSM_Murach chapter-15-slides
 
Avoiding and dealing with conflicting updates in Oak
Avoiding and dealing with conflicting updates in OakAvoiding and dealing with conflicting updates in Oak
Avoiding and dealing with conflicting updates in Oak
 
Testing Android apps based on Dagger and RxJava
Testing Android apps based on Dagger and RxJavaTesting Android apps based on Dagger and RxJava
Testing Android apps based on Dagger and RxJava
 
Moderne App-Architektur mit Dagger2 und RxJava
Moderne App-Architektur mit Dagger2 und RxJavaModerne App-Architektur mit Dagger2 und RxJava
Moderne App-Architektur mit Dagger2 und RxJava
 
Анастасия Войтова: Здоровая психологическая атмосфера в жизни разработчика, ...
Анастасия Войтова:  Здоровая психологическая атмосфера в жизни разработчика, ...Анастасия Войтова:  Здоровая психологическая атмосфера в жизни разработчика, ...
Анастасия Войтова: Здоровая психологическая атмосфера в жизни разработчика, ...
 
A realtime infrastructure for Android apps: Firebase may be what you need..an...
A realtime infrastructure for Android apps: Firebase may be what you need..an...A realtime infrastructure for Android apps: Firebase may be what you need..an...
A realtime infrastructure for Android apps: Firebase may be what you need..an...
 
Android Test Automation Workshop
Android Test Automation WorkshopAndroid Test Automation Workshop
Android Test Automation Workshop
 

Plus de Fabio Collini

Architectures in the compose world
Architectures in the compose worldArchitectures in the compose world
Architectures in the compose worldFabio Collini
 
Using hilt in a modularized project
Using hilt in a modularized projectUsing hilt in a modularized project
Using hilt in a modularized projectFabio Collini
 
Managing parallelism using coroutines
Managing parallelism using coroutinesManaging parallelism using coroutines
Managing parallelism using coroutinesFabio Collini
 
Kotlin Delegates in practice - Kotlin community conf
Kotlin Delegates in practice - Kotlin community confKotlin Delegates in practice - Kotlin community conf
Kotlin Delegates in practice - Kotlin community confFabio Collini
 
Kotlin delegates in practice - Kotlin Everywhere Stockholm
Kotlin delegates in practice - Kotlin Everywhere StockholmKotlin delegates in practice - Kotlin Everywhere Stockholm
Kotlin delegates in practice - Kotlin Everywhere StockholmFabio Collini
 
Solid principles in practice the clean architecture - Droidcon Italy
Solid principles in practice the clean architecture - Droidcon ItalySolid principles in practice the clean architecture - Droidcon Italy
Solid principles in practice the clean architecture - Droidcon ItalyFabio Collini
 
SOLID principles in practice: the Clean Architecture - Devfest Emila Romagna
SOLID principles in practice: the Clean Architecture - Devfest Emila RomagnaSOLID principles in practice: the Clean Architecture - Devfest Emila Romagna
SOLID principles in practice: the Clean Architecture - Devfest Emila RomagnaFabio Collini
 
SOLID principles in practice: the Clean Architecture
SOLID principles in practice: the Clean ArchitectureSOLID principles in practice: the Clean Architecture
SOLID principles in practice: the Clean ArchitectureFabio Collini
 
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf MilanFrom Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf MilanFabio Collini
 
Async code on kotlin: rx java or/and coroutines - Kotlin Night Turin
Async code on kotlin: rx java or/and coroutines - Kotlin Night TurinAsync code on kotlin: rx java or/and coroutines - Kotlin Night Turin
Async code on kotlin: rx java or/and coroutines - Kotlin Night TurinFabio Collini
 
Recap Google I/O 2018
Recap Google I/O 2018Recap Google I/O 2018
Recap Google I/O 2018Fabio Collini
 
From java to kotlin beyond alt+shift+cmd+k - Droidcon italy
From java to kotlin beyond alt+shift+cmd+k - Droidcon italyFrom java to kotlin beyond alt+shift+cmd+k - Droidcon italy
From java to kotlin beyond alt+shift+cmd+k - Droidcon italyFabio Collini
 
From java to kotlin beyond alt+shift+cmd+k
From java to kotlin beyond alt+shift+cmd+kFrom java to kotlin beyond alt+shift+cmd+k
From java to kotlin beyond alt+shift+cmd+kFabio Collini
 
Testing Android apps based on Dagger and RxJava Droidcon UK
Testing Android apps based on Dagger and RxJava Droidcon UKTesting Android apps based on Dagger and RxJava Droidcon UK
Testing Android apps based on Dagger and RxJava Droidcon UKFabio Collini
 
Intro to Retrofit 2 and RxJava2
Intro to Retrofit 2 and RxJava2Intro to Retrofit 2 and RxJava2
Intro to Retrofit 2 and RxJava2Fabio Collini
 

Plus de Fabio Collini (15)

Architectures in the compose world
Architectures in the compose worldArchitectures in the compose world
Architectures in the compose world
 
Using hilt in a modularized project
Using hilt in a modularized projectUsing hilt in a modularized project
Using hilt in a modularized project
 
Managing parallelism using coroutines
Managing parallelism using coroutinesManaging parallelism using coroutines
Managing parallelism using coroutines
 
Kotlin Delegates in practice - Kotlin community conf
Kotlin Delegates in practice - Kotlin community confKotlin Delegates in practice - Kotlin community conf
Kotlin Delegates in practice - Kotlin community conf
 
Kotlin delegates in practice - Kotlin Everywhere Stockholm
Kotlin delegates in practice - Kotlin Everywhere StockholmKotlin delegates in practice - Kotlin Everywhere Stockholm
Kotlin delegates in practice - Kotlin Everywhere Stockholm
 
Solid principles in practice the clean architecture - Droidcon Italy
Solid principles in practice the clean architecture - Droidcon ItalySolid principles in practice the clean architecture - Droidcon Italy
Solid principles in practice the clean architecture - Droidcon Italy
 
SOLID principles in practice: the Clean Architecture - Devfest Emila Romagna
SOLID principles in practice: the Clean Architecture - Devfest Emila RomagnaSOLID principles in practice: the Clean Architecture - Devfest Emila Romagna
SOLID principles in practice: the Clean Architecture - Devfest Emila Romagna
 
SOLID principles in practice: the Clean Architecture
SOLID principles in practice: the Clean ArchitectureSOLID principles in practice: the Clean Architecture
SOLID principles in practice: the Clean Architecture
 
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf MilanFrom Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
 
Async code on kotlin: rx java or/and coroutines - Kotlin Night Turin
Async code on kotlin: rx java or/and coroutines - Kotlin Night TurinAsync code on kotlin: rx java or/and coroutines - Kotlin Night Turin
Async code on kotlin: rx java or/and coroutines - Kotlin Night Turin
 
Recap Google I/O 2018
Recap Google I/O 2018Recap Google I/O 2018
Recap Google I/O 2018
 
From java to kotlin beyond alt+shift+cmd+k - Droidcon italy
From java to kotlin beyond alt+shift+cmd+k - Droidcon italyFrom java to kotlin beyond alt+shift+cmd+k - Droidcon italy
From java to kotlin beyond alt+shift+cmd+k - Droidcon italy
 
From java to kotlin beyond alt+shift+cmd+k
From java to kotlin beyond alt+shift+cmd+kFrom java to kotlin beyond alt+shift+cmd+k
From java to kotlin beyond alt+shift+cmd+k
 
Testing Android apps based on Dagger and RxJava Droidcon UK
Testing Android apps based on Dagger and RxJava Droidcon UKTesting Android apps based on Dagger and RxJava Droidcon UK
Testing Android apps based on Dagger and RxJava Droidcon UK
 
Intro to Retrofit 2 and RxJava2
Intro to Retrofit 2 and RxJava2Intro to Retrofit 2 and RxJava2
Intro to Retrofit 2 and RxJava2
 

Dernier

Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...apidays
 
AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024The Digital Insurer
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?Igalia
 
A Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source MilvusA Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source MilvusZilliz
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProduct Anonymous
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native ApplicationsWSO2
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherRemote DBA Services
 
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot ModelNavi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot ModelDeepika Singh
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobeapidays
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDropbox
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdflior mazor
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsNanddeep Nachan
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century educationjfdjdjcjdnsjd
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 

Dernier (20)

Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
A Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source MilvusA Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source Milvus
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot ModelNavi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 

Testable Android Apps DroidCon Italy 2015

  • 2. DroidCon Italy – Torino – April 2015 – @fabioCollini 2 Fabio Collini @fabioCollini linkedin.com/in/fabiocollini Folder Organizer cosenonjaviste.it nana bianca Freapp instal.com Rain tomorrow?
  • 3. DroidCon Italy – Torino – April 2015 – @fabioCollini 3 Quick survey Do you write automated tests?
  • 4. DroidCon Italy – Torino – April 2015 – @fabioCollini 4 Return of Investment - ROI Net profit Investment
  • 5. DroidCon Italy – Torino – April 2015 – @fabioCollini 5 Agenda 1. Legacy code 2. Dependency Injection 3. Mockito 4. Dagger 5. Dagger & Android 6. Model View Presenter
  • 6. DroidCon Italy – Torino – April 2015 – @fabioCollini 6 TestableAndroidAppsDroidCon15 https://github.com/fabioCollini/ TestableAndroidAppsDroidCon15
  • 7. DroidCon Italy - Torino - April 2015 - @fabioCollini 1Legacy code
  • 8. DroidCon Italy – Torino – April 2015 – @fabioCollini 8 Legacy code Edit and pray Vs Cover and modify Legacy code is code without unit tests
  • 9. DroidCon Italy – Torino – April 2015 – @fabioCollini 9 Instrumentation tests run on a device (real or emulated) high code coverage Vs JVM tests fast low code coverage
  • 10. DroidCon Italy – Torino – April 2015 – @fabioCollini 10 Espresso public class PostListActivityTest { //see https://gist.github.com/JakeWharton/1c2f2cadab2ddd97f9fb
 @Rule
 public ActivityRule<PostListActivity> rule = new ActivityRule<>(PostListActivity.class);
 
 } @Test public void showListActivity() {
 onView(withText("???")) .check(matches(isDisplayed()));
 }
 @Test public void showErrorLayoutOnServerError() {
 //???
 onView(withId(R.id.error_layout)) .check(matches(isDisplayed())); }
  • 11. DroidCon Italy – Torino – April 2015 – @fabioCollini 11 Legacy code dilemma When we change code, we should have tests in place. To put tests in place, we often have to change code. Michael Feathers
  • 12. DroidCon Italy – Torino – April 2015 – @fabioCollini 12 TestablePostListActivity public class TestablePostListActivity extends PostListActivity {
 
 public static Observable<List<Post>> result;
 
 @Override protected Observable<List<Post>> createListObservable() {
 return result;
 }
 }
  • 13. DroidCon Italy – Torino – April 2015 – @fabioCollini 13 PostListActivityTest public class PostListActivityTest { 
 @Rule public ActivityRule<TestablePostListActivity> rule = new ActivityRule<>( TestablePostListActivity.class, false );
 
 @Test public void showListActivity() {
 TestablePostListActivity.result = Observable.just(
 createPost(1), createPost(2), createPost(3)
 ).toList();
 
 rule.launchActivity();
 
 onView(withText("title 1”)) .check(matches(isDisplayed()));
 }
  • 14. DroidCon Italy – Torino – April 2015 – @fabioCollini 14 PostListActivityTest @Test public void checkErrorLayoutDisplayed() {
 TestablePostListActivity.result = Observable.error(new IOException());
 
 rule.launchActivity();
 
 onView(withId(R.id.error_layout)) .check(matches(isDisplayed()));
 }
  • 15. DroidCon Italy – Torino – April 2015 – @fabioCollini 15 Legacy code Not the perfect solution First step to increase coverage Then modify and refactor
  • 16. DroidCon Italy - Torino - April 2015 - @fabioCollini 2Dependency Injection
  • 17. DroidCon Italy – Torino – April 2015 – @fabioCollini 17 PostBatch public void execute() {
 PostResponse postResponse = createService().listPosts();
 EmailSender emailSender = new EmailSender();
 
 List<Post> posts = postResponse.getPosts();
 for (Post post : posts) {
 emailSender.sendEmail(post);
 }
 }
 
 private static WordPressService createService() {
 //...
 }
  • 18. DroidCon Italy – Torino – April 2015 – @fabioCollini 18 PostBatch WordPressService EmailSender Class under test Collaborator Collaborator
  • 19. DroidCon Italy – Torino – April 2015 – @fabioCollini 19 PostBatchTest public class PostBatchTest {
 
 private PostBatch postBatch = new PostBatch();
 
 @Test
 public void testExecute() {
 postBatch.execute();
 //???
 }
 }
  • 20. DroidCon Italy – Torino – April 2015 – @fabioCollini 20 Inversion Of Control private WordPressService wordPressService;
 
 private EmailSender emailSender;
 
 public PostBatch(WordPressService wordPressService, EmailSender emailSender) {
 this.wordPressService = wordPressService;
 this.emailSender = emailSender;
 }
 
 public void execute() {
 PostResponse postResponse = wordPressService.listPosts();
 List<Post> posts = postResponse.getPosts();
 for (Post post : posts) {
 emailSender.sendEmail(post);
 }
 }
  • 21. DroidCon Italy – Torino – April 2015 – @fabioCollini 21 Dependency Injection public class Main {
 
 public static void main(String[] args) {
 new PostBatch( createService(), new EmailSender() ).execute();
 }
 
 private static WordPressService createService() {
 //...
 }
 }
  • 22. DroidCon Italy – Torino – April 2015 – @fabioCollini 22 WordPressServiceStub public class WordPressServiceStub implements WordPressService {
 
 private PostResponse postResponse;
 
 public WordPressServiceStub(PostResponse postResponse) {
 this.postResponse = postResponse;
 }
 
 @Override public PostResponse listPosts() {
 return postResponse;
 }
 }
  • 23. DroidCon Italy – Torino – April 2015 – @fabioCollini 23 EmailSenderSpy public class EmailSenderSpy extends EmailSender {
 
 private int emailCount;
 
 @Override public void sendEmail(Post p) {
 emailCount++;
 }
 
 public int getEmailCount() {
 return emailCount;
 }
 }
  • 24. DroidCon Italy – Torino – April 2015 – @fabioCollini 24 PostBatch WordPressService EmailSender Stub Spy
  • 25. DroidCon Italy – Torino – April 2015 – @fabioCollini 25 Test doubles private PostBatch postBatch;
 
 private EmailSenderSpy emailSenderSpy;
 
 private WordPressServiceStub serviceStub; @Test
 public void testExecute() {
 postBatch.execute();
 assertEquals(3, emailSenderSpy.getEmailCount());
 } @Before public void init() {
 emailSenderSpy = new EmailSenderSpy();
 serviceStub = new WordPressServiceStub( new PostResponse(new Post(), new Post(), new Post()) );
 postBatch = new PostBatch(serviceStub, emailSenderSpy);
 }

  • 26. DroidCon Italy - Torino - April 2015 - @fabioCollini 3Mockito
  • 27. DroidCon Italy – Torino – April 2015 – @fabioCollini 27 Mockito private WordPressService service;
 private EmailSender emailSender;
 private PostBatch postBatch;
 @Before public void init() {
 emailSender = Mockito.mock(EmailSender.class);
 service = Mockito.mock(WordPressService.class);
 postBatch = new PostBatch(service, emailSender);
 } @Test public void testExecute() {
 when(service.listPosts()).thenReturn( new PostResponse(new Post(), new Post(), new Post()));
 
 postBatch.execute();
 
 verify(emailSender, times(3)).sendEmail(any(Post.class));
 } ArrangeActAssert
  • 28. DroidCon Italy – Torino – April 2015 – @fabioCollini 28 @InjectMocks @RunWith(MockitoJUnitRunner.class)
 public class PostBatchTest {
 
 @Mock WordPressService service;
 
 @Mock EmailSender sender;
 
 @InjectMocks PostBatch postBatch;
 
 @Test
 public void testExecute() {
 when(service.listPosts()).thenReturn( new PostResponse(new Post(), new Post(), new Post()));
 
 postBatch.execute();
 
 verify(sender, times(3)).sendEmail(any(Post.class));
 }
 }
  • 29. DroidCon Italy - Torino - April 2015 - @fabioCollini 4Dagger
  • 30. DroidCon Italy – Torino – April 2015 – @fabioCollini 30 Dagger A fast dependency injector for Android and Java v1 developed at Square https://github.com/square/dagger v2 developed at Google https://github.com/google/dagger Configuration using annotations and Java classes Based on annotation processing (no reflection)
  • 31. DroidCon Italy – Torino – April 2015 – @fabioCollini 31 Module @Module
 public class MainModule { 
 @Provides @Singleton EmailSender provideEmailSender() {
 return new EmailSender();
 }
 
 @Provides @Singleton WordPressService provideService() {
 //...
 }
 
 @Provides PostBatch providePostsBatch( WordPressService wordPressService, EmailSender emailSender) {
 return new PostBatch(wordPressService, emailSender);
 }
 }
  • 32. DroidCon Italy – Torino – April 2015 – @fabioCollini 32 PostBatch WordPressService EmailSender Component Main
  • 33. DroidCon Italy – Torino – April 2015 – @fabioCollini 33 Component @Singleton
 @Component(modules = MainModule.class)
 public interface MainComponent {
 PostBatch getBatch();
 } public class Main {
 public static void main(String[] args) {
 MainComponent component = DaggerMainComponent.create(); PostBatch batch = component.getBatch();
 batch.execute();
 }
 }
  • 34. DroidCon Italy – Torino – April 2015 – @fabioCollini 34 Inject annotation public class PostBatch {
 private WordPressService wordPressService;
 private EmailSender emailSender;
 
 @Inject public PostBatch( WordPressService wordPressService, EmailSender emailSender) {
 this.wordPressService = wordPressService;
 this.emailSender = emailSender;
 } } public class PostBatch {
 @Inject WordPressService wordPressService;
 @Inject EmailSender emailSender;
 @Inject public PostBatch() {
 }
 }
  • 35. DroidCon Italy - Torino - April 2015 - @fabioCollini 5Dagger & Android
  • 36. DroidCon Italy – Torino – April 2015 – @fabioCollini 36 PostListActivity WordPressService ShareActivity ShareExecutor
  • 37. DroidCon Italy – Torino – April 2015 – @fabioCollini 37 ShareExecutor public class ShareExecutor {
 private Context context; 
 public ShareExecutor(Context context) {
 this.context = context;
 }
 
 public void startSendActivity(String title, String body) {
 Intent intent = new Intent();
 intent.setAction(Intent.ACTION_SEND);
 intent.putExtra(Intent.EXTRA_TITLE, title);
 intent.putExtra(Intent.EXTRA_TEXT, body);
 intent.setType("text/plain");
 Intent chooserIntent = Intent.createChooser(intent, context.getResources().getText(R.string.share));
 chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(chooserIntent); }
 }
  • 38. DroidCon Italy – Torino – April 2015 – @fabioCollini 38 ApplicationModule @Module public class ApplicationModule {
 private Application application;
 public ApplicationModule(Application application) {
 this.application = application;
 } 
 @Provides @Singleton WordPressService providesService() {
 //...
 }
 @Provides @Singleton ShareExecutor shareExecutor() {
 return new ShareExecutor(application);
 }
 }
  • 39. DroidCon Italy – Torino – April 2015 – @fabioCollini 39 ApplicationComponent @Singleton @Component(modules = ApplicationModule.class)
 public interface ApplicationComponent { 
 void inject(PostListActivity activity);
 void inject(ShareActivity activity); }
  • 40. DroidCon Italy – Torino – April 2015 – @fabioCollini 40 Component PostListActivity Application ShareActivity ShareExecutorWordPressService
  • 41. DroidCon Italy – Torino – April 2015 – @fabioCollini 41 Application public class CnjApplication extends Application {
 
 private ApplicationComponent component;
 
 @Override public void onCreate() {
 super.onCreate();
 component = DaggerApplicationComponent.builder()
 .applicationModule(new ApplicationModule(this))
 .build();
 }
 
 public ApplicationComponent getComponent() {
 return component;
 }
 
 public void setComponent(ApplicationComponent c) {
 this.component = c;
 }
 }
  • 42. DroidCon Italy – Torino – April 2015 – @fabioCollini 42 PostListActivity public class PostListActivity extends ActionBarActivity {
 //...
 @Inject WordPressService wordPressService;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 CnjApplication app = (CnjApplication) getApplicationContext(); ApplicationComponent component = app.getComponent();
 component.inject(this);
 
 //...
 }
 //...
 }
  • 43. DroidCon Italy – Torino – April 2015 – @fabioCollini 43 Component PostListActivity Application ShareExecutorWordPressService TestComponent MockMock Test
  • 44. DroidCon Italy – Torino – April 2015 – @fabioCollini 44 TestModule @Module
 public class TestModule {
 @Provides @Singleton ShareExecutor provideShareExecutor() {
 return Mockito.mock(ShareExecutor.class);
 }
 @Provides @Singleton WordPressService providesWordPressService() {
 return Mockito.mock(WordPressService.class);
 }
 }
  • 45. DroidCon Italy – Torino – April 2015 – @fabioCollini 45 TestComponent @Singleton
 @Component(modules = TestModule.class)
 public interface TestComponent extends ApplicationComponent {
 void inject(PostListActivityTest test);
 
 void inject(ShareActivityTest test);
 }
  • 46. DroidCon Italy – Torino – April 2015 – @fabioCollini 46 PostListActivityTest public class PostListActivityTest {
 
 @Inject WordPressService wordPressService;
 
 @Rule public ActivityRule<PostListActivity> rule = new ActivityRule<>(PostListActivity.class, false);
 @Before public void setUp() {
 TestComponent component = DaggerTestComponent.create();
 CnjApplication application = (CnjApplication) rule.getApplication();
 application.setComponent(component);
 component.inject(this);
 } //...
  • 47. DroidCon Italy – Torino – April 2015 – @fabioCollini 47 PostListActivityTest @Test public void showListActivity() {
 when(wordPressService.listPosts()).thenReturn( Observable.just(new PostResponse(createPost(1), createPost(2), createPost(3))));
 
 rule.launchActivity();
 
 onView(withText("title 1”)) .check(matches(isDisplayed()));
 }
  • 48. DroidCon Italy – Torino – April 2015 – @fabioCollini 48 PostListActivityTest 
 @Test public void showErrorLayoutOnServerError() {
 when(wordPressService.listPosts()).thenReturn( Observable.error(new IOException("error!")));
 
 rule.launchActivity();
 
 onView(withId(R.id.error_layout)) .check(matches(isDisplayed()));
 }
  • 49. DroidCon Italy - Torino - April 2015 - @fabioCollini 6Model View Presenter
  • 50. DroidCon Italy – Torino – April 2015 – @fabioCollini 50 Model View Presenter View Presenter Model
  • 51. DroidCon Italy – Torino – April 2015 – @fabioCollini 51 View Presenter RetrofitService onClick update update(model) Model View Presenter RetrofitServiceModel request response
  • 52. DroidCon Italy – Torino – April 2015 – @fabioCollini 52 View Presenter MockService perform(click()) update update(model) Model request response EspressoTest View Presenter MockServiceModelEspressoTest onView verify when().thenReturn() onClick
  • 53. DroidCon Italy – Torino – April 2015 – @fabioCollini 53 MockView Presenter MockService onClick update update(model) Model request response JVM Test MockView Presenter MockServiceModelJVM Test verify verify assert when().thenReturn()
  • 54. DroidCon Italy – Torino – April 2015 – @fabioCollini 54 View Presenter init update(model) ModelEspressoTest View Presenter ModelEspressoTest onView create
  • 55. DroidCon Italy – Torino – April 2015 – @fabioCollini 55 Android Model View Presenter Activity (or Fragment) is the View All the business logic is in the Presenter Presenter is managed using Dagger Model is the Activity (or Fragment) state Presenter is retained on configuration change
  • 56. DroidCon Italy – Torino – April 2015 – @fabioCollini 56 PostListPresenter JVM Test @RunWith(MockitoJUnitRunner.class)
 public class PostListPresenterTest {
 
 @Mock WordPressService wordPressService;
 
 @Mock PostListActivity view;
 
 private PostListPresenter postListPresenter;
 
 @Before public void setUp() { SchedulerManager schedulerManager = new SchedulerManager( Schedulers.immediate(), Schedulers.immediate()); 
 postListPresenter = new PostListPresenter( wordPressService, schedulerManager );
 }
 //...
  • 57. DroidCon Italy – Torino – April 2015 – @fabioCollini 57 PostListPresenter JVM Test @Test
 public void loadingPosts() { when(wordPressService.listPosts()).thenReturn( Observable.just(new PostResponse(new Post(), new Post(), new Post())));
 
 PostListModel model = new PostListModel();
 postListPresenter.setModel(model);
 postListPresenter.resume(view);
 
 assertEquals(3, model.getItems().size());
 }
  • 58. DroidCon Italy – Torino – April 2015 – @fabioCollini 58 PostListPresenter JVM Test @Test
 public void clickOnItem() {
 PostListModel model = new PostListModel();
 model.setItems(Arrays.asList( createPost(1), createPost(2), createPost(3)));
 postListPresenter.setModel(model);
 postListPresenter.resume(view);
 
 postListPresenter.onItemClick(1);
 
 verify(view).startShareActivity( eq("title 2"), eq("name 2 last name 2nexcerpt 2"));
 }
  • 59. DroidCon Italy – Torino – April 2015 – @fabioCollini 59 SharePresenter JVM Test @RunWith(MockitoJUnitRunner.class)
 public class SharePresenterTest {
 
 @Mock ShareExecutor shareExecutor;
 
 @Mock ShareActivity view;
 
 @InjectMocks SharePresenter sharePresenter;
 
 @Test public void testValidationOk() { ShareModel model = new ShareModel();
 sharePresenter.init(view, model);
 
 sharePresenter.share("title", "body");
 
 verify(shareExecutor) .startSendActivity(eq("title"), eq("body"));
 }
 }
  • 60. DroidCon Italy – Torino – April 2015 – @fabioCollini 60 TL;DR Dagger Mockito Espresso UI tests JVM Presenter tests
  • 61. DroidCon Italy – Torino – April 2015 – @fabioCollini 61 Thanks for your attention! Questions? github.com/fabioCollini/ TestableAndroidAppsDroidCon15 github.com/google/dagger mockito.org cosenonjaviste.it/libri