├── app ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── values │ │ │ │ ├── styles.xml │ │ │ │ ├── dimens.xml │ │ │ │ └── strings.xml │ │ │ ├── values-w820dp │ │ │ │ └── dimens.xml │ │ │ └── layout │ │ │ │ ├── activity_detail.xml │ │ │ │ └── activity_main.xml │ │ └── java │ │ │ └── it │ │ │ └── cosenonjaviste │ │ │ └── testableandroidapps │ │ │ ├── mvplib │ │ │ ├── Presenter.java │ │ │ ├── MvpContext.java │ │ │ └── BaseActivity.java │ │ │ ├── MvpScope.java │ │ │ ├── model │ │ │ ├── WordPressService.java │ │ │ ├── PostResponse.java │ │ │ ├── Author.java │ │ │ └── Post.java │ │ │ ├── v2 │ │ │ ├── TestableShareActivity.java │ │ │ ├── TestablePostListActivity.java │ │ │ └── ShareActivity.java │ │ │ ├── v7 │ │ │ ├── ShareComponent.java │ │ │ ├── PostListComponent.java │ │ │ ├── PostListModel.java │ │ │ ├── ShareModel.java │ │ │ ├── SharePresenter.java │ │ │ └── PostListPresenter.java │ │ │ ├── v4 │ │ │ ├── ShareModel.java │ │ │ ├── PostListModel.java │ │ │ └── ShareActivity.java │ │ │ ├── SchedulerManager.java │ │ │ ├── CnjApplication.java │ │ │ ├── v5 │ │ │ ├── PostListModel.java │ │ │ ├── ShareModel.java │ │ │ ├── SharePresenter.java │ │ │ └── PostListPresenter.java │ │ │ ├── v6 │ │ │ ├── PostListModel.java │ │ │ ├── ShareModel.java │ │ │ ├── SharePresenter.java │ │ │ ├── PostListPresenter.java │ │ │ └── ShareActivity.java │ │ │ ├── v8 │ │ │ ├── PostListModel.java │ │ │ ├── ShareModel.java │ │ │ ├── SharePresenter.java │ │ │ ├── ShareActivity.java │ │ │ └── PostListActivity.java │ │ │ ├── v10 │ │ │ ├── ShareActivity.java │ │ │ ├── PostListModel.java │ │ │ ├── ShareModel.java │ │ │ ├── PostListActivity.java │ │ │ └── SharePresenter.java │ │ │ ├── ShareExecutor.java │ │ │ ├── v9 │ │ │ ├── PostListModel.java │ │ │ ├── ShareModel.java │ │ │ ├── ShareActivity.java │ │ │ ├── PostListActivity.java │ │ │ └── SharePresenter.java │ │ │ ├── PostViewHolder.java │ │ │ ├── ObservableHolder.java │ │ │ ├── ApplicationModule.java │ │ │ ├── PostAdapter.java │ │ │ ├── RetainedFragment.java │ │ │ ├── ApplicationComponent.java │ │ │ ├── v3 │ │ │ └── ShareActivity.java │ │ │ └── v1 │ │ │ └── ShareActivity.java │ ├── androidTest │ │ └── java │ │ │ └── it │ │ │ └── cosenonjaviste │ │ │ └── testableandroidapps │ │ │ ├── PostCreator.java │ │ │ ├── v3 │ │ │ ├── TestComponent.java │ │ │ ├── PostListActivityTest.java │ │ │ └── ShareActivityTest.java │ │ │ ├── v4 │ │ │ ├── TestComponent.java │ │ │ ├── PostListActivityTest.java │ │ │ └── ShareActivityTest.java │ │ │ ├── v5 │ │ │ ├── TestComponent.java │ │ │ ├── PostListActivityTest.java │ │ │ └── ShareActivityTest.java │ │ │ ├── v6 │ │ │ ├── TestComponent.java │ │ │ ├── PostListActivityTest.java │ │ │ └── ShareActivityTest.java │ │ │ ├── v7 │ │ │ ├── TestComponent.java │ │ │ ├── PostListActivityTest.java │ │ │ └── ShareActivityTest.java │ │ │ ├── TestModule.java │ │ │ ├── v1 │ │ │ ├── PostListActivityTest.java │ │ │ └── ShareActivityTest.java │ │ │ ├── utils │ │ │ ├── ErrorTextMatcher.java │ │ │ └── EspressoExecutor.java │ │ │ └── v2 │ │ │ ├── PostListActivityTest.java │ │ │ └── ShareActivityTest.java │ └── test │ │ └── java │ │ └── it │ │ └── cosenonjaviste │ │ └── testableandroidapps │ │ ├── mvplib │ │ ├── MvpTestContext.java │ │ └── FakeEditable.java │ │ ├── utils │ │ └── FileUtils.java │ │ ├── JsonParsingTest.java │ │ ├── v5 │ │ ├── SharePresenterTest.java │ │ └── PostListPresenterTest.java │ │ ├── v6 │ │ ├── SharePresenterTest.java │ │ └── PostListPresenterTest.java │ │ ├── v7 │ │ ├── SharePresenterTest.java │ │ └── PostListPresenterTest.java │ │ ├── v8 │ │ ├── SharePresenterTest.java │ │ └── PostListPresenterTest.java │ │ ├── v10 │ │ ├── SharePresenterTest.java │ │ └── PostListPresenterTest.java │ │ └── v9 │ │ ├── SharePresenterTest.java │ │ └── PostListPresenterTest.java └── proguard-rules.pro ├── dependencyinjection ├── .gitignore ├── src │ ├── main │ │ └── java │ │ │ └── it │ │ │ └── cosenonjaviste │ │ │ └── testableandroidapps │ │ │ ├── v1 │ │ │ ├── Main.java │ │ │ ├── EmailSender.java │ │ │ └── PostBatch.java │ │ │ ├── v3 │ │ │ ├── Main.java │ │ │ ├── MainComponent.java │ │ │ ├── EmailSender.java │ │ │ ├── PostBatch.java │ │ │ └── MainModule.java │ │ │ ├── v4 │ │ │ ├── Main.java │ │ │ ├── MainComponent.java │ │ │ ├── EmailSender.java │ │ │ ├── PostBatch.java │ │ │ └── MainModule.java │ │ │ ├── v5 │ │ │ ├── Main.java │ │ │ ├── MainComponent.java │ │ │ ├── EmailSender.java │ │ │ ├── MainModule.java │ │ │ └── PostBatch.java │ │ │ ├── v2 │ │ │ ├── EmailSender.java │ │ │ ├── Main.java │ │ │ └── PostBatch.java │ │ │ └── model │ │ │ ├── WordPressService.java │ │ │ ├── PostResponse.java │ │ │ ├── Author.java │ │ │ └── Post.java │ └── test │ │ └── java │ │ └── it │ │ └── cosenonjaviste │ │ └── testableandroidapps │ │ ├── v4 │ │ ├── TestComponent.java │ │ ├── TestModule.java │ │ └── PostBatchTest.java │ │ ├── v5 │ │ ├── TestComponent.java │ │ ├── TestModule.java │ │ ├── PostBatchTest.java │ │ └── PostBatchNoDaggerTest.java │ │ ├── v1 │ │ └── PostBatchTest.java │ │ ├── v2 │ │ ├── EmailSenderSpy.java │ │ ├── WordPressServiceStub.java │ │ ├── PostBatchTest.java │ │ ├── MockitoPostsBatchTest3.java │ │ ├── MockitoPostsBatchTest2.java │ │ └── MockitoPostBatchTest.java │ │ └── v3 │ │ └── PostBatchTest.java └── build.gradle ├── settings.gradle ├── .gitignore ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── README.md ├── gradle.properties └── gradlew.bat /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /dependencyinjection/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':dependencyinjection' 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea/* 4 | .DS_Store 5 | /build 6 | *.iml -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fabioCollini/TestableAndroidAppsDroidCon15/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fabioCollini/TestableAndroidAppsDroidCon15/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fabioCollini/TestableAndroidAppsDroidCon15/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fabioCollini/TestableAndroidAppsDroidCon15/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fabioCollini/TestableAndroidAppsDroidCon15/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /dependencyinjection/src/main/java/it/cosenonjaviste/testableandroidapps/v1/Main.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v1; 2 | 3 | public class Main { 4 | public static void main(String[] args) { 5 | new PostBatch().execute(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Apr 10 15:27:10 PDT 2013 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip 7 | -------------------------------------------------------------------------------- /dependencyinjection/src/main/java/it/cosenonjaviste/testableandroidapps/v3/Main.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v3; 2 | 3 | public class Main { 4 | public static void main(String[] args) { 5 | PostBatch batch = DaggerMainComponent.create().getBatch(); 6 | batch.execute(); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /dependencyinjection/src/main/java/it/cosenonjaviste/testableandroidapps/v4/Main.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v4; 2 | 3 | public class Main { 4 | public static void main(String[] args) { 5 | PostBatch batch = DaggerMainComponent.create().getBatch(); 6 | batch.execute(); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /dependencyinjection/src/main/java/it/cosenonjaviste/testableandroidapps/v5/Main.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v5; 2 | 3 | public class Main { 4 | public static void main(String[] args) { 5 | PostBatch batch = DaggerMainComponent.create().getBatch(); 6 | batch.execute(); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/mvplib/Presenter.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.mvplib; 2 | 3 | public interface Presenter { 4 | void resume(MvpContext mvpContext); 5 | 6 | void pause(); 7 | 8 | void destroy(); 9 | 10 | M createDefaultModel(); 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/MvpScope.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps; 2 | 3 | import java.lang.annotation.Retention; 4 | 5 | import javax.inject.Scope; 6 | 7 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 8 | 9 | @Scope 10 | @Retention(RUNTIME) 11 | public @interface MvpScope { 12 | } -------------------------------------------------------------------------------- /dependencyinjection/src/main/java/it/cosenonjaviste/testableandroidapps/v3/MainComponent.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v3; 2 | 3 | import javax.inject.Singleton; 4 | 5 | import dagger.Component; 6 | 7 | @Singleton 8 | @Component(modules = MainModule.class) 9 | public interface MainComponent { 10 | PostBatch getBatch(); 11 | } 12 | -------------------------------------------------------------------------------- /dependencyinjection/src/main/java/it/cosenonjaviste/testableandroidapps/v4/MainComponent.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v4; 2 | 3 | import javax.inject.Singleton; 4 | 5 | import dagger.Component; 6 | 7 | @Singleton 8 | @Component(modules = MainModule.class) 9 | public interface MainComponent { 10 | PostBatch getBatch(); 11 | } 12 | -------------------------------------------------------------------------------- /dependencyinjection/src/main/java/it/cosenonjaviste/testableandroidapps/v5/MainComponent.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v5; 2 | 3 | import javax.inject.Singleton; 4 | 5 | import dagger.Component; 6 | 7 | @Singleton 8 | @Component(modules = MainModule.class) 9 | public interface MainComponent { 10 | PostBatch getBatch(); 11 | } 12 | -------------------------------------------------------------------------------- /dependencyinjection/src/main/java/it/cosenonjaviste/testableandroidapps/v1/EmailSender.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v1; 2 | 3 | import it.cosenonjaviste.testableandroidapps.model.Post; 4 | 5 | public class EmailSender { 6 | public void sendEmail(Post p) { 7 | System.out.println("email " + p.getTitle() + " sent!"); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /dependencyinjection/src/main/java/it/cosenonjaviste/testableandroidapps/v2/EmailSender.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v2; 2 | 3 | import it.cosenonjaviste.testableandroidapps.model.Post; 4 | 5 | public class EmailSender { 6 | public void sendEmail(Post p) { 7 | System.out.println("email " + p.getTitle() + " sent!"); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /dependencyinjection/src/test/java/it/cosenonjaviste/testableandroidapps/v4/TestComponent.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v4; 2 | 3 | import javax.inject.Singleton; 4 | 5 | import dagger.Component; 6 | 7 | @Singleton 8 | @Component(modules = TestModule.class) 9 | public interface TestComponent { 10 | void inject(PostBatchTest test); 11 | } 12 | -------------------------------------------------------------------------------- /dependencyinjection/src/test/java/it/cosenonjaviste/testableandroidapps/v5/TestComponent.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v5; 2 | 3 | import javax.inject.Singleton; 4 | 5 | import dagger.Component; 6 | 7 | @Singleton 8 | @Component(modules = TestModule.class) 9 | public interface TestComponent { 10 | void inject(PostBatchTest test); 11 | } 12 | -------------------------------------------------------------------------------- /dependencyinjection/src/main/java/it/cosenonjaviste/testableandroidapps/model/WordPressService.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.model; 2 | 3 | import retrofit.http.GET; 4 | 5 | public interface WordPressService { 6 | @GET("/?json=get_recent_posts&count=10&exclude=attachments,thumbnail_images,content,title_plain,tags,custom_fields") PostResponse listPosts(); 7 | } -------------------------------------------------------------------------------- /dependencyinjection/src/main/java/it/cosenonjaviste/testableandroidapps/v3/EmailSender.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v3; 2 | 3 | import it.cosenonjaviste.testableandroidapps.model.Post; 4 | 5 | public class EmailSender { 6 | 7 | public void sendEmail(Post p) { 8 | System.out.println("email " + p.getTitle() + " sent!"); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/model/WordPressService.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.model; 2 | 3 | import retrofit.http.GET; 4 | import rx.Observable; 5 | 6 | public interface WordPressService { 7 | @GET("/?json=get_recent_posts&count=10&exclude=attachments,thumbnail_images,content,title_plain,tags,custom_fields") Observable listPosts(); 8 | } -------------------------------------------------------------------------------- /dependencyinjection/src/test/java/it/cosenonjaviste/testableandroidapps/v1/PostBatchTest.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v1; 2 | 3 | import org.junit.Test; 4 | 5 | public class PostBatchTest { 6 | 7 | private PostBatch postBatch = new PostBatch(); 8 | 9 | @Test 10 | public void testExecute() { 11 | postBatch.execute(); 12 | //??? 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/v2/TestableShareActivity.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v2; 2 | 3 | public class TestableShareActivity extends ShareActivity { 4 | 5 | public String shareTitle; 6 | 7 | public String shareBody; 8 | 9 | @Override protected void startSendActivity(String title, String body) { 10 | shareTitle = title; 11 | shareBody = body; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/v7/ShareComponent.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v7; 2 | 3 | import dagger.Component; 4 | import it.cosenonjaviste.testableandroidapps.ApplicationComponent; 5 | import it.cosenonjaviste.testableandroidapps.MvpScope; 6 | 7 | @MvpScope 8 | @Component(dependencies = ApplicationComponent.class) 9 | public interface ShareComponent { 10 | void inject(ShareActivity activity); 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/v7/PostListComponent.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v7; 2 | 3 | import dagger.Component; 4 | import it.cosenonjaviste.testableandroidapps.ApplicationComponent; 5 | import it.cosenonjaviste.testableandroidapps.MvpScope; 6 | 7 | @MvpScope 8 | @Component(dependencies = ApplicationComponent.class) 9 | public interface PostListComponent { 10 | void inject(PostListActivity activity); 11 | } 12 | -------------------------------------------------------------------------------- /dependencyinjection/src/test/java/it/cosenonjaviste/testableandroidapps/v2/EmailSenderSpy.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v2; 2 | 3 | import it.cosenonjaviste.testableandroidapps.model.Post; 4 | 5 | public class EmailSenderSpy extends EmailSender { 6 | 7 | private int emailCount; 8 | 9 | @Override public void sendEmail(Post p) { 10 | emailCount++; 11 | } 12 | 13 | public int getEmailCount() { 14 | return emailCount; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /dependencyinjection/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | 3 | dependencies { 4 | compile 'com.squareup.okhttp:okhttp:2.0.0' 5 | compile 'com.squareup.retrofit:retrofit:1.9.0' 6 | compile 'com.google.dagger:dagger:2.0' 7 | compile 'com.google.dagger:dagger-compiler:2.0' 8 | 9 | testCompile 'junit:junit:4.12' 10 | testCompile 'org.mockito:mockito-core:1.9.5' 11 | testCompile 'org.assertj:assertj-core:1.7.0' 12 | testCompile 'com.google.dagger:dagger-compiler:2.0' 13 | } -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/model/PostResponse.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.model; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | 6 | public class PostResponse { 7 | private List posts; 8 | 9 | public PostResponse() { 10 | } 11 | 12 | public PostResponse(Post... posts) { 13 | this.posts = Arrays.asList(posts); 14 | } 15 | 16 | public List getPosts() { 17 | return posts; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/v2/TestablePostListActivity.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v2; 2 | 3 | import java.util.List; 4 | 5 | import it.cosenonjaviste.testableandroidapps.model.Post; 6 | import rx.Observable; 7 | 8 | public class TestablePostListActivity extends PostListActivity { 9 | 10 | public static Observable> result; 11 | 12 | @Override protected Observable> createListObservable() { 13 | return result; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /dependencyinjection/src/main/java/it/cosenonjaviste/testableandroidapps/v4/EmailSender.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v4; 2 | 3 | import javax.inject.Inject; 4 | import javax.inject.Singleton; 5 | 6 | import it.cosenonjaviste.testableandroidapps.model.Post; 7 | 8 | @Singleton 9 | public class EmailSender { 10 | 11 | @Inject public EmailSender() { 12 | } 13 | 14 | public void sendEmail(Post p) { 15 | System.out.println("email " + p.getTitle() + " sent!"); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/it/cosenonjaviste/testableandroidapps/PostCreator.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps; 2 | 3 | import java.util.Date; 4 | 5 | import it.cosenonjaviste.testableandroidapps.model.Author; 6 | import it.cosenonjaviste.testableandroidapps.model.Post; 7 | 8 | public class PostCreator { 9 | public static Post createPost(int id) { 10 | return new Post(id, new Author(id, "name " + id, "last name " + id), "title " + id, new Date(), "url" + id, "excerpt " + id); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/src/androidTest/java/it/cosenonjaviste/testableandroidapps/v3/TestComponent.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v3; 2 | 3 | import javax.inject.Singleton; 4 | 5 | import dagger.Component; 6 | import it.cosenonjaviste.testableandroidapps.ApplicationComponent; 7 | import it.cosenonjaviste.testableandroidapps.TestModule; 8 | 9 | @Singleton 10 | @Component(modules = TestModule.class) 11 | public interface TestComponent extends ApplicationComponent { 12 | void inject(PostListActivityTest test); 13 | 14 | void inject(ShareActivityTest test); 15 | } 16 | -------------------------------------------------------------------------------- /app/src/androidTest/java/it/cosenonjaviste/testableandroidapps/v4/TestComponent.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v4; 2 | 3 | import javax.inject.Singleton; 4 | 5 | import dagger.Component; 6 | import it.cosenonjaviste.testableandroidapps.ApplicationComponent; 7 | import it.cosenonjaviste.testableandroidapps.TestModule; 8 | 9 | @Singleton 10 | @Component(modules = TestModule.class) 11 | public interface TestComponent extends ApplicationComponent { 12 | void inject(PostListActivityTest test); 13 | 14 | void inject(ShareActivityTest test); 15 | } 16 | -------------------------------------------------------------------------------- /app/src/androidTest/java/it/cosenonjaviste/testableandroidapps/v5/TestComponent.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v5; 2 | 3 | import javax.inject.Singleton; 4 | 5 | import dagger.Component; 6 | import it.cosenonjaviste.testableandroidapps.ApplicationComponent; 7 | import it.cosenonjaviste.testableandroidapps.TestModule; 8 | 9 | @Singleton 10 | @Component(modules = TestModule.class) 11 | public interface TestComponent extends ApplicationComponent { 12 | void inject(PostListActivityTest test); 13 | 14 | void inject(ShareActivityTest test); 15 | } 16 | -------------------------------------------------------------------------------- /app/src/androidTest/java/it/cosenonjaviste/testableandroidapps/v6/TestComponent.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v6; 2 | 3 | import javax.inject.Singleton; 4 | 5 | import dagger.Component; 6 | import it.cosenonjaviste.testableandroidapps.ApplicationComponent; 7 | import it.cosenonjaviste.testableandroidapps.TestModule; 8 | 9 | @Singleton 10 | @Component(modules = TestModule.class) 11 | public interface TestComponent extends ApplicationComponent { 12 | void inject(PostListActivityTest test); 13 | 14 | void inject(ShareActivityTest test); 15 | } 16 | -------------------------------------------------------------------------------- /app/src/androidTest/java/it/cosenonjaviste/testableandroidapps/v7/TestComponent.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v7; 2 | 3 | import javax.inject.Singleton; 4 | 5 | import dagger.Component; 6 | import it.cosenonjaviste.testableandroidapps.ApplicationComponent; 7 | import it.cosenonjaviste.testableandroidapps.TestModule; 8 | 9 | @Singleton 10 | @Component(modules = TestModule.class) 11 | public interface TestComponent extends ApplicationComponent { 12 | void inject(PostListActivityTest test); 13 | 14 | void inject(ShareActivityTest test); 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/v4/ShareModel.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v4; 2 | 3 | import org.parceler.Parcel; 4 | 5 | @Parcel 6 | public class ShareModel { 7 | String title; 8 | 9 | String body; 10 | 11 | public String getTitle() { 12 | return title; 13 | } 14 | 15 | public void setTitle(String title) { 16 | this.title = title; 17 | } 18 | 19 | public String getBody() { 20 | return body; 21 | } 22 | 23 | public void setBody(String body) { 24 | this.body = body; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | TestableAndroidAppsDroidCon15 3 | 4 | Hello world! 5 | Settings 6 | Share 7 | Error loading data 8 | Reload 9 | Loading... 10 | Title 11 | Text 12 | Mandatory field 13 | 14 | -------------------------------------------------------------------------------- /dependencyinjection/src/main/java/it/cosenonjaviste/testableandroidapps/model/PostResponse.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.model; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | 6 | public class PostResponse { 7 | private List posts; 8 | 9 | public PostResponse() { 10 | } 11 | 12 | public PostResponse(List posts) { 13 | this.posts = posts; 14 | } 15 | 16 | public PostResponse(Post... posts) { 17 | this.posts = Arrays.asList(posts); 18 | } 19 | 20 | public List getPosts() { 21 | return posts; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /dependencyinjection/src/test/java/it/cosenonjaviste/testableandroidapps/v2/WordPressServiceStub.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v2; 2 | 3 | import it.cosenonjaviste.testableandroidapps.model.PostResponse; 4 | import it.cosenonjaviste.testableandroidapps.model.WordPressService; 5 | 6 | public class WordPressServiceStub implements WordPressService { 7 | 8 | private PostResponse postResponse; 9 | 10 | public WordPressServiceStub(PostResponse postResponse) { 11 | this.postResponse = postResponse; 12 | } 13 | 14 | @Override public PostResponse listPosts() { 15 | return postResponse; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /dependencyinjection/src/test/java/it/cosenonjaviste/testableandroidapps/v4/TestModule.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v4; 2 | 3 | import org.mockito.Mockito; 4 | 5 | import javax.inject.Singleton; 6 | 7 | import dagger.Module; 8 | import dagger.Provides; 9 | import it.cosenonjaviste.testableandroidapps.model.WordPressService; 10 | 11 | @Module 12 | public class TestModule { 13 | @Provides @Singleton EmailSender provideEmailSender() { 14 | return Mockito.mock(EmailSender.class); 15 | } 16 | 17 | @Provides @Singleton WordPressService provideWordPressService() { 18 | return Mockito.mock(WordPressService.class); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TestableAndroidAppsDroidCon15 2 | 3 | Droidcon Italy 2015 example 4 | 5 | 6 | -------------------------------------------------------------------------------- /dependencyinjection/src/main/java/it/cosenonjaviste/testableandroidapps/v5/EmailSender.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v5; 2 | 3 | import java.util.Random; 4 | 5 | import javax.inject.Inject; 6 | import javax.inject.Singleton; 7 | 8 | import it.cosenonjaviste.testableandroidapps.model.Post; 9 | 10 | @Singleton 11 | public class EmailSender { 12 | 13 | @Inject public EmailSender() { 14 | } 15 | 16 | public void sendEmail(Post p) { 17 | try { 18 | Thread.sleep(new Random().nextInt(500)); 19 | } catch (InterruptedException ignored) { 20 | } 21 | System.out.println("email " + p.getTitle() + " sent!"); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/SchedulerManager.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps; 2 | 3 | import rx.Observable; 4 | import rx.Scheduler; 5 | 6 | public class SchedulerManager { 7 | 8 | private Observable.Transformer transformer; 9 | 10 | public SchedulerManager(Scheduler io, Scheduler mainThread) { 11 | transformer = new Observable.Transformer() { 12 | @Override public Observable call(Observable observable) { 13 | return observable.subscribeOn(io).observeOn(mainThread); 14 | } 15 | }; 16 | } 17 | 18 | public Observable.Transformer schedule() { 19 | return transformer; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/fabiocollini/android-sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/CnjApplication.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps; 2 | 3 | import android.app.Application; 4 | 5 | public class CnjApplication extends Application { 6 | 7 | private ApplicationComponent component; 8 | 9 | @Override public void onCreate() { 10 | super.onCreate(); 11 | component = DaggerApplicationComponent.builder() 12 | .applicationModule(new ApplicationModule(this)) 13 | .build(); 14 | } 15 | 16 | public ApplicationComponent getComponent() { 17 | return component; 18 | } 19 | 20 | public void setComponent(ApplicationComponent component) { 21 | this.component = component; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/v4/PostListModel.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v4; 2 | 3 | import org.parceler.Parcel; 4 | 5 | import java.util.List; 6 | 7 | import it.cosenonjaviste.testableandroidapps.model.Post; 8 | 9 | @Parcel 10 | public class PostListModel { 11 | List items; 12 | 13 | String errorText; 14 | 15 | public List getItems() { 16 | return items; 17 | } 18 | 19 | public void setItems(List items) { 20 | this.items = items; 21 | } 22 | 23 | public void setErrorText(String errorText) { 24 | this.errorText = errorText; 25 | } 26 | 27 | public String getErrorText() { 28 | return errorText; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/v5/PostListModel.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v5; 2 | 3 | import org.parceler.Parcel; 4 | 5 | import java.util.List; 6 | 7 | import it.cosenonjaviste.testableandroidapps.model.Post; 8 | 9 | @Parcel 10 | public class PostListModel { 11 | List items; 12 | 13 | String errorText; 14 | 15 | public List getItems() { 16 | return items; 17 | } 18 | 19 | public void setItems(List items) { 20 | this.items = items; 21 | } 22 | 23 | public void setErrorText(String errorText) { 24 | this.errorText = errorText; 25 | } 26 | 27 | public String getErrorText() { 28 | return errorText; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/v6/PostListModel.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v6; 2 | 3 | import org.parceler.Parcel; 4 | 5 | import java.util.List; 6 | 7 | import it.cosenonjaviste.testableandroidapps.model.Post; 8 | 9 | @Parcel 10 | public class PostListModel { 11 | List items; 12 | 13 | String errorText; 14 | 15 | public List getItems() { 16 | return items; 17 | } 18 | 19 | public void setItems(List items) { 20 | this.items = items; 21 | } 22 | 23 | public void setErrorText(String errorText) { 24 | this.errorText = errorText; 25 | } 26 | 27 | public String getErrorText() { 28 | return errorText; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/v7/PostListModel.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v7; 2 | 3 | import org.parceler.Parcel; 4 | 5 | import java.util.List; 6 | 7 | import it.cosenonjaviste.testableandroidapps.model.Post; 8 | 9 | @Parcel 10 | public class PostListModel { 11 | List items; 12 | 13 | String errorText; 14 | 15 | public List getItems() { 16 | return items; 17 | } 18 | 19 | public void setItems(List items) { 20 | this.items = items; 21 | } 22 | 23 | public void setErrorText(String errorText) { 24 | this.errorText = errorText; 25 | } 26 | 27 | public String getErrorText() { 28 | return errorText; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/v8/PostListModel.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v8; 2 | 3 | import org.parceler.Parcel; 4 | 5 | import java.util.List; 6 | 7 | import it.cosenonjaviste.testableandroidapps.model.Post; 8 | 9 | @Parcel 10 | public class PostListModel { 11 | List items; 12 | 13 | String errorText; 14 | 15 | public List getItems() { 16 | return items; 17 | } 18 | 19 | public void setItems(List items) { 20 | this.items = items; 21 | } 22 | 23 | public void setErrorText(String errorText) { 24 | this.errorText = errorText; 25 | } 26 | 27 | public String getErrorText() { 28 | return errorText; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /dependencyinjection/src/main/java/it/cosenonjaviste/testableandroidapps/v4/PostBatch.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v4; 2 | 3 | import java.util.List; 4 | 5 | import javax.inject.Inject; 6 | 7 | import it.cosenonjaviste.testableandroidapps.model.Post; 8 | import it.cosenonjaviste.testableandroidapps.model.PostResponse; 9 | import it.cosenonjaviste.testableandroidapps.model.WordPressService; 10 | 11 | public class PostBatch { 12 | 13 | @Inject WordPressService wordPressService; 14 | 15 | @Inject EmailSender emailSender; 16 | 17 | @Inject public PostBatch() { 18 | } 19 | 20 | public void execute() { 21 | PostResponse postResponse = wordPressService.listPosts(); 22 | 23 | List posts = postResponse.getPosts(); 24 | for (Post post : posts) { 25 | emailSender.sendEmail(post); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/v10/ShareActivity.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v10; 2 | 3 | import it.cosenonjaviste.testableandroidapps.ApplicationComponent; 4 | import it.cosenonjaviste.testableandroidapps.CnjApplication; 5 | import it.cosenonjaviste.testableandroidapps.R; 6 | import it.cosenonjaviste.testableandroidapps.mvplib.BaseActivity; 7 | import it.cosenonjaviste.testableandroidapps.mvplib.Presenter; 8 | 9 | 10 | public class ShareActivity extends BaseActivity { 11 | 12 | protected int getLayoutId() { 13 | return R.layout.activity_detail; 14 | } 15 | 16 | protected Presenter createPresenter() { 17 | ApplicationComponent component = ((CnjApplication) getApplicationContext()).getComponent(); 18 | return component.getSharePresenterV10(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /dependencyinjection/src/main/java/it/cosenonjaviste/testableandroidapps/v4/MainModule.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v4; 2 | 3 | import com.google.gson.GsonBuilder; 4 | 5 | import javax.inject.Singleton; 6 | 7 | import dagger.Module; 8 | import dagger.Provides; 9 | import it.cosenonjaviste.testableandroidapps.model.WordPressService; 10 | import retrofit.RestAdapter; 11 | import retrofit.converter.GsonConverter; 12 | 13 | @Module 14 | public class MainModule { 15 | @Provides @Singleton WordPressService provideWordPressService() { 16 | RestAdapter restAdapter = new RestAdapter.Builder() 17 | .setEndpoint("http://www.cosenonjaviste.it/") 18 | .setConverter(new GsonConverter(new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create())) 19 | .build(); 20 | return restAdapter.create(WordPressService.class); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/ShareExecutor.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | 6 | public class ShareExecutor { 7 | private Context context; 8 | 9 | public ShareExecutor(Context context) { 10 | this.context = context; 11 | } 12 | 13 | public void startSendActivity(String title, String body) { 14 | Intent intent = new Intent(); 15 | intent.setAction(Intent.ACTION_SEND); 16 | intent.putExtra(Intent.EXTRA_TITLE, title); 17 | intent.putExtra(Intent.EXTRA_TEXT, body); 18 | intent.setType("text/plain"); 19 | Intent chooserIntent = Intent.createChooser(intent, context.getResources().getText(R.string.share)); 20 | chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 21 | context.startActivity(chooserIntent); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /dependencyinjection/src/main/java/it/cosenonjaviste/testableandroidapps/v2/Main.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v2; 2 | 3 | import com.google.gson.GsonBuilder; 4 | 5 | import it.cosenonjaviste.testableandroidapps.model.WordPressService; 6 | import retrofit.RestAdapter; 7 | import retrofit.converter.GsonConverter; 8 | 9 | public class Main { 10 | 11 | public static void main(String[] args) { 12 | new PostBatch(createService(), new EmailSender()).execute(); 13 | } 14 | 15 | private static WordPressService createService() { 16 | //... 17 | RestAdapter restAdapter = new RestAdapter.Builder() 18 | .setEndpoint("http://www.cosenonjaviste.it/") 19 | .setConverter(new GsonConverter(new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create())) 20 | .build(); 21 | return restAdapter.create(WordPressService.class); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/v10/PostListModel.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v10; 2 | 3 | import org.parceler.Parcel; 4 | 5 | import java.util.Arrays; 6 | import java.util.List; 7 | 8 | import it.cosenonjaviste.testableandroidapps.model.Post; 9 | 10 | @Parcel 11 | public class PostListModel { 12 | List items; 13 | 14 | String errorText; 15 | 16 | public PostListModel() { 17 | } 18 | 19 | public PostListModel(Post... items) { 20 | this.items = Arrays.asList(items); 21 | } 22 | 23 | public List getItems() { 24 | return items; 25 | } 26 | 27 | public void setItems(List items) { 28 | this.items = items; 29 | } 30 | 31 | public void setErrorText(String errorText) { 32 | this.errorText = errorText; 33 | } 34 | 35 | public String getErrorText() { 36 | return errorText; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/v9/PostListModel.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v9; 2 | 3 | import org.parceler.Parcel; 4 | 5 | import java.util.Arrays; 6 | import java.util.List; 7 | 8 | import it.cosenonjaviste.testableandroidapps.model.Post; 9 | 10 | @Parcel 11 | public class PostListModel { 12 | List items; 13 | 14 | String errorText; 15 | 16 | public PostListModel() { 17 | } 18 | 19 | public PostListModel(Post... items) { 20 | this.items = Arrays.asList(items); 21 | } 22 | 23 | public List getItems() { 24 | return items; 25 | } 26 | 27 | public void setItems(List items) { 28 | this.items = items; 29 | } 30 | 31 | public void setErrorText(String errorText) { 32 | this.errorText = errorText; 33 | } 34 | 35 | public String getErrorText() { 36 | return errorText; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /dependencyinjection/src/test/java/it/cosenonjaviste/testableandroidapps/v5/TestModule.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v5; 2 | 3 | import org.mockito.Mockito; 4 | 5 | import java.util.concurrent.Executor; 6 | 7 | import javax.inject.Singleton; 8 | 9 | import dagger.Module; 10 | import dagger.Provides; 11 | import it.cosenonjaviste.testableandroidapps.model.WordPressService; 12 | 13 | @Module 14 | public class TestModule { 15 | @Provides @Singleton EmailSender provideEmailSender() { 16 | return Mockito.mock(EmailSender.class); 17 | } 18 | 19 | @Provides @Singleton WordPressService provideWordPressService() { 20 | return Mockito.mock(WordPressService.class); 21 | } 22 | 23 | @Provides @Singleton Executor provideExecutor() { 24 | return new Executor() { 25 | @Override public void execute(Runnable command) { 26 | command.run(); 27 | } 28 | }; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /dependencyinjection/src/main/java/it/cosenonjaviste/testableandroidapps/v2/PostBatch.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v2; 2 | 3 | import java.util.List; 4 | 5 | import it.cosenonjaviste.testableandroidapps.model.Post; 6 | import it.cosenonjaviste.testableandroidapps.model.PostResponse; 7 | import it.cosenonjaviste.testableandroidapps.model.WordPressService; 8 | 9 | public class PostBatch { 10 | 11 | private WordPressService wordPressService; 12 | 13 | private EmailSender emailSender; 14 | 15 | public PostBatch(WordPressService wordPressService, EmailSender emailSender) { 16 | this.wordPressService = wordPressService; 17 | this.emailSender = emailSender; 18 | } 19 | 20 | public void execute() { 21 | PostResponse postResponse = wordPressService.listPosts(); 22 | 23 | List posts = postResponse.getPosts(); 24 | for (Post post : posts) { 25 | emailSender.sendEmail(post); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /dependencyinjection/src/test/java/it/cosenonjaviste/testableandroidapps/v2/PostBatchTest.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v2; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | 6 | import it.cosenonjaviste.testableandroidapps.model.Post; 7 | import it.cosenonjaviste.testableandroidapps.model.PostResponse; 8 | 9 | import static org.junit.Assert.assertEquals; 10 | 11 | public class PostBatchTest { 12 | 13 | private PostBatch postBatch; 14 | 15 | private EmailSenderSpy emailSenderSpy; 16 | 17 | private WordPressServiceStub serviceStub; 18 | 19 | @Before public void init() { 20 | emailSenderSpy = new EmailSenderSpy(); 21 | serviceStub = new WordPressServiceStub(new PostResponse(new Post(), new Post(), new Post())); 22 | postBatch = new PostBatch(serviceStub, emailSenderSpy); 23 | } 24 | 25 | @Test 26 | public void testExecute() { 27 | postBatch.execute(); 28 | assertEquals(3, emailSenderSpy.getEmailCount()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/PostViewHolder.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps; 2 | 3 | import android.text.Html; 4 | import android.text.format.DateUtils; 5 | import android.view.View; 6 | import android.widget.TextView; 7 | 8 | import it.cosenonjaviste.testableandroidapps.model.Post; 9 | 10 | public class PostViewHolder { 11 | 12 | private final TextView text1; 13 | private final TextView text2; 14 | 15 | public PostViewHolder(View convertView) { 16 | text1 = (TextView) convertView.findViewById(android.R.id.text1); 17 | text2 = (TextView) convertView.findViewById(android.R.id.text2); 18 | } 19 | 20 | public void populate(Post post) { 21 | CharSequence dateFormatted = DateUtils.getRelativeTimeSpanString(text1.getContext(), post.getDate().getTime()); 22 | 23 | text1.setText(Html.fromHtml(post.getTitle())); 24 | text2.setText(dateFormatted + ", " + post.getAuthor().getFirstName() + " " + post.getAuthor().getLastName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/v5/ShareModel.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v5; 2 | 3 | import org.parceler.Parcel; 4 | 5 | @Parcel 6 | public class ShareModel { 7 | String title; 8 | 9 | String body; 10 | 11 | int titleError; 12 | 13 | int bodyError; 14 | 15 | public String getTitle() { 16 | return title; 17 | } 18 | 19 | public void setTitle(String title) { 20 | this.title = title; 21 | } 22 | 23 | public String getBody() { 24 | return body; 25 | } 26 | 27 | public void setBody(String body) { 28 | this.body = body; 29 | } 30 | 31 | public void setTitleError(int titleError) { 32 | this.titleError = titleError; 33 | } 34 | 35 | public int getTitleError() { 36 | return titleError; 37 | } 38 | 39 | public void setBodyError(int bodyError) { 40 | this.bodyError = bodyError; 41 | } 42 | 43 | public int getBodyError() { 44 | return bodyError; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /dependencyinjection/src/main/java/it/cosenonjaviste/testableandroidapps/v3/PostBatch.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v3; 2 | 3 | import java.util.List; 4 | 5 | import javax.inject.Inject; 6 | 7 | import it.cosenonjaviste.testableandroidapps.model.Post; 8 | import it.cosenonjaviste.testableandroidapps.model.PostResponse; 9 | import it.cosenonjaviste.testableandroidapps.model.WordPressService; 10 | 11 | public class PostBatch { 12 | 13 | private WordPressService wordPressService; 14 | 15 | private EmailSender emailSender; 16 | 17 | @Inject public PostBatch(WordPressService wordPressService, EmailSender emailSender) { 18 | this.wordPressService = wordPressService; 19 | this.emailSender = emailSender; 20 | } 21 | 22 | public void execute() { 23 | PostResponse postResponse = wordPressService.listPosts(); 24 | 25 | List posts = postResponse.getPosts(); 26 | for (Post post : posts) { 27 | emailSender.sendEmail(post); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/androidTest/java/it/cosenonjaviste/testableandroidapps/TestModule.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps; 2 | 3 | import org.mockito.Mockito; 4 | 5 | import javax.inject.Singleton; 6 | 7 | import dagger.Module; 8 | import dagger.Provides; 9 | import it.cosenonjaviste.testableandroidapps.model.WordPressService; 10 | import it.cosenonjaviste.testableandroidapps.utils.EspressoExecutor; 11 | import rx.android.schedulers.AndroidSchedulers; 12 | import rx.schedulers.Schedulers; 13 | 14 | @Module 15 | public class TestModule { 16 | @Provides @Singleton ShareExecutor provideShareExecutor() { 17 | return Mockito.mock(ShareExecutor.class); 18 | } 19 | 20 | @Provides @Singleton WordPressService providesWordPressService() { 21 | return Mockito.mock(WordPressService.class); 22 | } 23 | 24 | @Provides @Singleton SchedulerManager providesSchedulerManager() { 25 | return new SchedulerManager(Schedulers.from(EspressoExecutor.getCachedThreadPool()), AndroidSchedulers.mainThread()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/model/Author.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.model; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | import org.parceler.Parcel; 6 | 7 | @Parcel 8 | public class Author { 9 | long id; 10 | 11 | @SerializedName("first_name") 12 | String firstName; 13 | 14 | @SerializedName("last_name") 15 | String lastName; 16 | 17 | String email; 18 | 19 | public Author() { 20 | } 21 | 22 | public Author(long id, String firstName, String lastName) { 23 | this(); 24 | this.id = id; 25 | this.firstName = firstName; 26 | this.lastName = lastName; 27 | } 28 | 29 | public long getId() { 30 | return id; 31 | } 32 | 33 | public String getName() { 34 | return firstName + " " + lastName; 35 | } 36 | 37 | public String getFirstName() { 38 | return firstName; 39 | } 40 | 41 | public String getLastName() { 42 | return lastName; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/test/java/it/cosenonjaviste/testableandroidapps/mvplib/MvpTestContext.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.mvplib; 2 | 3 | import android.widget.TextView; 4 | 5 | public class MvpTestContext extends MvpContext { 6 | 7 | private TestInjector injector = new TestInjector(); 8 | 9 | public MvpTestContext(V view, Presenter presenter) { 10 | this.model = presenter.createDefaultModel(); 11 | this.view = view; 12 | this.presenter = presenter; 13 | 14 | injector.inject(presenter); 15 | } 16 | 17 | public T getView(int viewId) { 18 | return injector.getView(viewId); 19 | } 20 | 21 | public TextView getTextView(int viewId) { 22 | return injector.getTextView(viewId); 23 | } 24 | 25 | public void clickOnView(int viewId) { 26 | injector.clickOnView(viewId); 27 | } 28 | 29 | public void clickOnItem(int viewId, int position) { 30 | injector.clickOnItem(viewId, position); 31 | } 32 | 33 | public void setModel(M model) { 34 | this.model = model; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /dependencyinjection/src/main/java/it/cosenonjaviste/testableandroidapps/v5/MainModule.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v5; 2 | 3 | import com.google.gson.GsonBuilder; 4 | 5 | import java.util.concurrent.Executor; 6 | import java.util.concurrent.Executors; 7 | 8 | import javax.inject.Singleton; 9 | 10 | import dagger.Module; 11 | import dagger.Provides; 12 | import it.cosenonjaviste.testableandroidapps.model.WordPressService; 13 | import retrofit.RestAdapter; 14 | import retrofit.converter.GsonConverter; 15 | 16 | @Module 17 | public class MainModule { 18 | @Provides @Singleton WordPressService provideWordPressService() { 19 | RestAdapter restAdapter = new RestAdapter.Builder() 20 | .setEndpoint("http://www.cosenonjaviste.it/") 21 | .setConverter(new GsonConverter(new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create())) 22 | .build(); 23 | return restAdapter.create(WordPressService.class); 24 | } 25 | 26 | @Provides @Singleton Executor provideExecutor() { 27 | return Executors.newFixedThreadPool(5); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /dependencyinjection/src/main/java/it/cosenonjaviste/testableandroidapps/model/Author.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.model; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | public class Author implements Comparable { 6 | long id; 7 | 8 | @SerializedName("first_name") 9 | String firstName; 10 | 11 | @SerializedName("last_name") 12 | String lastName; 13 | 14 | String email; 15 | 16 | public Author() { 17 | } 18 | 19 | public Author(long id, String firstName, String lastName) { 20 | this(); 21 | this.id = id; 22 | this.firstName = firstName; 23 | this.lastName = lastName; 24 | } 25 | 26 | public long getId() { 27 | return id; 28 | } 29 | 30 | public String getName() { 31 | return firstName + " " + lastName; 32 | } 33 | 34 | public String getFirstName() { 35 | return firstName; 36 | } 37 | 38 | public String getLastName() { 39 | return lastName; 40 | } 41 | 42 | @Override public int compareTo(Author o) { 43 | return Long.compare(id, o.id); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /dependencyinjection/src/main/java/it/cosenonjaviste/testableandroidapps/model/Post.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.model; 2 | 3 | import java.util.Date; 4 | 5 | public class Post { 6 | long id; 7 | Author author; 8 | String title; 9 | Date date; 10 | String url; 11 | String excerpt; 12 | 13 | public Post() { 14 | } 15 | 16 | public Post(long id, Author author, String title, Date date, String url, String excerpt) { 17 | this(); 18 | this.id = id; 19 | this.author = author; 20 | this.title = title; 21 | this.date = date; 22 | this.url = url; 23 | this.excerpt = excerpt; 24 | } 25 | 26 | public long getId() { 27 | return id; 28 | } 29 | 30 | public Author getAuthor() { 31 | return author; 32 | } 33 | 34 | public String getTitle() { 35 | return title; 36 | } 37 | 38 | public Date getDate() { 39 | return date; 40 | } 41 | 42 | public String getUrl() { 43 | return url; 44 | } 45 | 46 | public String getExcerpt() { 47 | return excerpt; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/src/androidTest/java/it/cosenonjaviste/testableandroidapps/v1/PostListActivityTest.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v1; 2 | 3 | import android.support.test.rule.ActivityTestRule; 4 | 5 | import org.junit.Rule; 6 | import org.junit.Test; 7 | 8 | import it.cosenonjaviste.testableandroidapps.R; 9 | 10 | import static android.support.test.espresso.Espresso.onView; 11 | import static android.support.test.espresso.assertion.ViewAssertions.matches; 12 | import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; 13 | import static android.support.test.espresso.matcher.ViewMatchers.withId; 14 | import static android.support.test.espresso.matcher.ViewMatchers.withText; 15 | 16 | public class PostListActivityTest { 17 | @Rule public final ActivityTestRule rule = new ActivityTestRule<>(PostListActivity.class); 18 | 19 | @Test public void showListActivity() { 20 | onView(withText("???")).check(matches(isDisplayed())); 21 | } 22 | 23 | @Test public void showErrorLayoutOnServerError() { 24 | //??? 25 | onView(withId(R.id.error_layout)).check(matches(isDisplayed())); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/ObservableHolder.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps; 2 | 3 | import rx.Observable; 4 | import rx.Subscription; 5 | import rx.observables.ConnectableObservable; 6 | import rx.subscriptions.Subscriptions; 7 | 8 | public class ObservableHolder { 9 | private Subscription connectableSubscription = Subscriptions.empty(); 10 | 11 | private ConnectableObservable observable; 12 | 13 | 14 | public void bind(ConnectableObservable observable) { 15 | this.observable = observable; 16 | connectableSubscription = observable.connect(); 17 | } 18 | 19 | public void destroy() { 20 | connectableSubscription.unsubscribe(); 21 | } 22 | 23 | public Observable getObservable() { 24 | if (observable == null) { 25 | return Observable.empty(); 26 | } 27 | return observable; 28 | } 29 | 30 | public boolean isRunning() { 31 | return observable != null; 32 | } 33 | 34 | public void clear() { 35 | observable = null; 36 | connectableSubscription = Subscriptions.empty(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/model/Post.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.model; 2 | 3 | import org.parceler.Parcel; 4 | 5 | import java.util.Date; 6 | 7 | @Parcel 8 | public class Post { 9 | long id; 10 | Author author; 11 | String title; 12 | Date date; 13 | String url; 14 | String excerpt; 15 | 16 | public Post() { 17 | } 18 | 19 | public Post(long id, Author author, String title, Date date, String url, String excerpt) { 20 | this.id = id; 21 | this.author = author; 22 | this.title = title; 23 | this.date = date; 24 | this.url = url; 25 | this.excerpt = excerpt; 26 | } 27 | 28 | public long getId() { 29 | return id; 30 | } 31 | 32 | public Author getAuthor() { 33 | return author; 34 | } 35 | 36 | public String getTitle() { 37 | return title; 38 | } 39 | 40 | public Date getDate() { 41 | return date; 42 | } 43 | 44 | public String getUrl() { 45 | return url; 46 | } 47 | 48 | public String getExcerpt() { 49 | return excerpt; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/v6/ShareModel.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v6; 2 | 3 | import org.parceler.Parcel; 4 | 5 | @Parcel 6 | public class ShareModel { 7 | String title; 8 | 9 | String body; 10 | 11 | int titleError; 12 | 13 | int bodyError; 14 | 15 | public ShareModel() { 16 | } 17 | 18 | public ShareModel(String title, String body) { 19 | this.title = title; 20 | this.body = body; 21 | } 22 | 23 | public String getTitle() { 24 | return title; 25 | } 26 | 27 | public void setTitle(String title) { 28 | this.title = title; 29 | } 30 | 31 | public String getBody() { 32 | return body; 33 | } 34 | 35 | public void setBody(String body) { 36 | this.body = body; 37 | } 38 | 39 | public void setTitleError(int titleError) { 40 | this.titleError = titleError; 41 | } 42 | 43 | public int getTitleError() { 44 | return titleError; 45 | } 46 | 47 | public void setBodyError(int bodyError) { 48 | this.bodyError = bodyError; 49 | } 50 | 51 | public int getBodyError() { 52 | return bodyError; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/v7/ShareModel.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v7; 2 | 3 | import org.parceler.Parcel; 4 | 5 | @Parcel 6 | public class ShareModel { 7 | String title; 8 | 9 | String body; 10 | 11 | int titleError; 12 | 13 | int bodyError; 14 | 15 | public ShareModel() { 16 | } 17 | 18 | public ShareModel(String title, String body) { 19 | this.title = title; 20 | this.body = body; 21 | } 22 | 23 | public String getTitle() { 24 | return title; 25 | } 26 | 27 | public void setTitle(String title) { 28 | this.title = title; 29 | } 30 | 31 | public String getBody() { 32 | return body; 33 | } 34 | 35 | public void setBody(String body) { 36 | this.body = body; 37 | } 38 | 39 | public void setTitleError(int titleError) { 40 | this.titleError = titleError; 41 | } 42 | 43 | public int getTitleError() { 44 | return titleError; 45 | } 46 | 47 | public void setBodyError(int bodyError) { 48 | this.bodyError = bodyError; 49 | } 50 | 51 | public int getBodyError() { 52 | return bodyError; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/v8/ShareModel.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v8; 2 | 3 | import org.parceler.Parcel; 4 | 5 | @Parcel 6 | public class ShareModel { 7 | String title; 8 | 9 | String body; 10 | 11 | int titleError; 12 | 13 | int bodyError; 14 | 15 | public ShareModel() { 16 | } 17 | 18 | public ShareModel(String title, String body) { 19 | this.title = title; 20 | this.body = body; 21 | } 22 | 23 | public String getTitle() { 24 | return title; 25 | } 26 | 27 | public void setTitle(String title) { 28 | this.title = title; 29 | } 30 | 31 | public String getBody() { 32 | return body; 33 | } 34 | 35 | public void setBody(String body) { 36 | this.body = body; 37 | } 38 | 39 | public void setTitleError(int titleError) { 40 | this.titleError = titleError; 41 | } 42 | 43 | public int getTitleError() { 44 | return titleError; 45 | } 46 | 47 | public void setBodyError(int bodyError) { 48 | this.bodyError = bodyError; 49 | } 50 | 51 | public int getBodyError() { 52 | return bodyError; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/v9/ShareModel.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v9; 2 | 3 | import org.parceler.Parcel; 4 | 5 | @Parcel 6 | public class ShareModel { 7 | String title; 8 | 9 | String body; 10 | 11 | int titleError; 12 | 13 | int bodyError; 14 | 15 | public ShareModel() { 16 | } 17 | 18 | public ShareModel(String title, String body) { 19 | this.title = title; 20 | this.body = body; 21 | } 22 | 23 | public String getTitle() { 24 | return title; 25 | } 26 | 27 | public void setTitle(String title) { 28 | this.title = title; 29 | } 30 | 31 | public String getBody() { 32 | return body; 33 | } 34 | 35 | public void setBody(String body) { 36 | this.body = body; 37 | } 38 | 39 | public void setTitleError(int titleError) { 40 | this.titleError = titleError; 41 | } 42 | 43 | public int getTitleError() { 44 | return titleError; 45 | } 46 | 47 | public void setBodyError(int bodyError) { 48 | this.bodyError = bodyError; 49 | } 50 | 51 | public int getBodyError() { 52 | return bodyError; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/v10/ShareModel.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v10; 2 | 3 | import org.parceler.Parcel; 4 | 5 | @Parcel 6 | public class ShareModel { 7 | String title; 8 | 9 | String body; 10 | 11 | int titleError; 12 | 13 | int bodyError; 14 | 15 | public ShareModel() { 16 | } 17 | 18 | public ShareModel(String title, String body) { 19 | this.title = title; 20 | this.body = body; 21 | } 22 | 23 | public String getTitle() { 24 | return title; 25 | } 26 | 27 | public void setTitle(String title) { 28 | this.title = title; 29 | } 30 | 31 | public String getBody() { 32 | return body; 33 | } 34 | 35 | public void setBody(String body) { 36 | this.body = body; 37 | } 38 | 39 | public void setTitleError(int titleError) { 40 | this.titleError = titleError; 41 | } 42 | 43 | public int getTitleError() { 44 | return titleError; 45 | } 46 | 47 | public void setBodyError(int bodyError) { 48 | this.bodyError = bodyError; 49 | } 50 | 51 | public int getBodyError() { 52 | return bodyError; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /dependencyinjection/src/main/java/it/cosenonjaviste/testableandroidapps/v3/MainModule.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v3; 2 | 3 | import com.google.gson.GsonBuilder; 4 | 5 | import javax.inject.Singleton; 6 | 7 | import dagger.Module; 8 | import dagger.Provides; 9 | import it.cosenonjaviste.testableandroidapps.model.WordPressService; 10 | import retrofit.RestAdapter; 11 | import retrofit.converter.GsonConverter; 12 | 13 | @Module 14 | public class MainModule { 15 | @Provides @Singleton EmailSender provideEmailSender() { 16 | return new EmailSender(); 17 | } 18 | 19 | @Provides @Singleton WordPressService provideWordPressService() { 20 | //... 21 | RestAdapter restAdapter = new RestAdapter.Builder() 22 | .setEndpoint("http://www.cosenonjaviste.it/") 23 | .setConverter(new GsonConverter(new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create())) 24 | .build(); 25 | return restAdapter.create(WordPressService.class); 26 | } 27 | 28 | @Provides PostBatch providePostsBatch(WordPressService worpressService, EmailSender emailSender) { 29 | return new PostBatch(worpressService, emailSender); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /dependencyinjection/src/test/java/it/cosenonjaviste/testableandroidapps/v3/PostBatchTest.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v3; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.mockito.InjectMocks; 6 | import org.mockito.Mock; 7 | import org.mockito.runners.MockitoJUnitRunner; 8 | 9 | import it.cosenonjaviste.testableandroidapps.model.Post; 10 | import it.cosenonjaviste.testableandroidapps.model.PostResponse; 11 | import it.cosenonjaviste.testableandroidapps.model.WordPressService; 12 | 13 | import static org.mockito.Matchers.any; 14 | import static org.mockito.Mockito.times; 15 | import static org.mockito.Mockito.verify; 16 | import static org.mockito.Mockito.when; 17 | 18 | @RunWith(MockitoJUnitRunner.class) 19 | public class PostBatchTest { 20 | 21 | @Mock WordPressService service; 22 | 23 | @Mock EmailSender sender; 24 | 25 | @InjectMocks PostBatch postBatch; 26 | 27 | @Test 28 | public void testExecute() { 29 | when(service.listPosts()) 30 | .thenReturn(new PostResponse(new Post(), new Post(), new Post())); 31 | 32 | postBatch.execute(); 33 | 34 | verify(sender, times(3)).sendEmail(any(Post.class)); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /dependencyinjection/src/test/java/it/cosenonjaviste/testableandroidapps/v4/PostBatchTest.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v4; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | 6 | import javax.inject.Inject; 7 | 8 | import it.cosenonjaviste.testableandroidapps.model.Post; 9 | import it.cosenonjaviste.testableandroidapps.model.PostResponse; 10 | import it.cosenonjaviste.testableandroidapps.model.WordPressService; 11 | 12 | import static org.mockito.Matchers.any; 13 | import static org.mockito.Mockito.times; 14 | import static org.mockito.Mockito.verify; 15 | import static org.mockito.Mockito.when; 16 | 17 | public class PostBatchTest { 18 | 19 | @Inject WordPressService wordPressService; 20 | 21 | @Inject EmailSender emailSender; 22 | 23 | @Inject PostBatch postBatch; 24 | 25 | @Before public void init() { 26 | DaggerTestComponent.create().inject(this); 27 | } 28 | 29 | @Test 30 | public void testExecute() { 31 | when(wordPressService.listPosts()) 32 | .thenReturn(new PostResponse(new Post(), new Post(), new Post())); 33 | 34 | postBatch.execute(); 35 | 36 | verify(emailSender, times(3)).sendEmail(any(Post.class)); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /dependencyinjection/src/test/java/it/cosenonjaviste/testableandroidapps/v5/PostBatchTest.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v5; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | 6 | import javax.inject.Inject; 7 | 8 | import it.cosenonjaviste.testableandroidapps.model.Post; 9 | import it.cosenonjaviste.testableandroidapps.model.PostResponse; 10 | import it.cosenonjaviste.testableandroidapps.model.WordPressService; 11 | 12 | import static org.mockito.Matchers.any; 13 | import static org.mockito.Mockito.times; 14 | import static org.mockito.Mockito.verify; 15 | import static org.mockito.Mockito.when; 16 | 17 | public class PostBatchTest { 18 | 19 | @Inject WordPressService wordPressService; 20 | 21 | @Inject EmailSender emailSender; 22 | 23 | @Inject PostBatch postBatch; 24 | 25 | @Before public void init() { 26 | DaggerTestComponent.create().inject(this); 27 | } 28 | 29 | @Test 30 | public void testExecute() { 31 | when(wordPressService.listPosts()) 32 | .thenReturn(new PostResponse(new Post(), new Post(), new Post())); 33 | 34 | postBatch.execute(); 35 | 36 | verify(emailSender, times(3)).sendEmail(any(Post.class)); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/test/java/it/cosenonjaviste/testableandroidapps/utils/FileUtils.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.utils; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.FileInputStream; 6 | import java.io.IOException; 7 | import java.io.InputStreamReader; 8 | 9 | public class FileUtils { 10 | 11 | public static String readFile(String fileName) throws IOException { 12 | StringBuilder b = new StringBuilder(); 13 | BufferedReader reader = null; 14 | try { 15 | File file = new File("app/src/test/resources/" + fileName); 16 | if (!file.exists()) { 17 | file = new File("src/test/resources/" + fileName); 18 | } 19 | reader = new BufferedReader(new InputStreamReader(new FileInputStream(file))); 20 | String line; 21 | while ((line = reader.readLine()) != null) { 22 | b.append(line).append("\n"); 23 | } 24 | } finally { 25 | try { 26 | if (reader != null) { 27 | reader.close(); 28 | } 29 | } catch (IOException e) { 30 | } 31 | } 32 | return b.toString(); 33 | } 34 | } -------------------------------------------------------------------------------- /dependencyinjection/src/test/java/it/cosenonjaviste/testableandroidapps/v2/MockitoPostsBatchTest3.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v2; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.mockito.InjectMocks; 6 | import org.mockito.Mock; 7 | import org.mockito.runners.MockitoJUnitRunner; 8 | 9 | import it.cosenonjaviste.testableandroidapps.model.Post; 10 | import it.cosenonjaviste.testableandroidapps.model.PostResponse; 11 | import it.cosenonjaviste.testableandroidapps.model.WordPressService; 12 | 13 | import static org.mockito.Matchers.any; 14 | import static org.mockito.Mockito.times; 15 | import static org.mockito.Mockito.verify; 16 | import static org.mockito.Mockito.when; 17 | 18 | @RunWith(MockitoJUnitRunner.class) 19 | public class MockitoPostsBatchTest3 { 20 | 21 | @Mock WordPressService service; 22 | 23 | @Mock EmailSender sender; 24 | 25 | @InjectMocks PostBatch postBatch; 26 | 27 | @Test 28 | public void testExecute() { 29 | when(service.listPosts()) 30 | .thenReturn(new PostResponse(new Post(), new Post(), new Post())); 31 | 32 | postBatch.execute(); 33 | 34 | verify(sender, times(3)).sendEmail(any(Post.class)); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/androidTest/java/it/cosenonjaviste/testableandroidapps/utils/ErrorTextMatcher.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.utils; 2 | 3 | import android.view.View; 4 | import android.widget.EditText; 5 | 6 | import org.hamcrest.Description; 7 | import org.hamcrest.Matcher; 8 | import org.hamcrest.TypeSafeMatcher; 9 | 10 | import static android.support.test.internal.util.Checks.checkNotNull; 11 | 12 | public class ErrorTextMatcher extends TypeSafeMatcher { 13 | private final String expectedError; 14 | 15 | private ErrorTextMatcher(String expectedError) { 16 | this.expectedError = checkNotNull(expectedError); 17 | } 18 | 19 | @Override 20 | public boolean matchesSafely(View view) { 21 | if (!(view instanceof EditText)) { 22 | return false; 23 | } 24 | EditText editText = (EditText) view; 25 | return expectedError.equals(editText.getError()); 26 | } 27 | 28 | @Override 29 | public void describeTo(Description description) { 30 | description.appendText("with error: " + expectedError); 31 | } 32 | 33 | public static Matcher hasErrorText(String expectedError) { 34 | return new ErrorTextMatcher(expectedError); 35 | } 36 | } -------------------------------------------------------------------------------- /dependencyinjection/src/main/java/it/cosenonjaviste/testableandroidapps/v5/PostBatch.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v5; 2 | 3 | import java.util.List; 4 | import java.util.concurrent.Executor; 5 | 6 | import javax.inject.Inject; 7 | 8 | import it.cosenonjaviste.testableandroidapps.model.Post; 9 | import it.cosenonjaviste.testableandroidapps.model.PostResponse; 10 | import it.cosenonjaviste.testableandroidapps.model.WordPressService; 11 | 12 | public class PostBatch { 13 | 14 | private WordPressService service; 15 | 16 | private EmailSender sender; 17 | 18 | private Executor executor; 19 | 20 | @Inject public PostBatch(WordPressService service, EmailSender sender, Executor executor) { 21 | this.service = service; 22 | this.sender = sender; 23 | this.executor = executor; 24 | } 25 | 26 | public void execute() { 27 | PostResponse postResponse = service.listPosts(); 28 | 29 | List posts = postResponse.getPosts(); 30 | for (Post post : posts) { 31 | executor.execute(new Runnable() { 32 | @Override public void run() { 33 | sender.sendEmail(post); 34 | } 35 | }); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /dependencyinjection/src/main/java/it/cosenonjaviste/testableandroidapps/v1/PostBatch.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v1; 2 | 3 | import com.google.gson.GsonBuilder; 4 | 5 | import java.util.List; 6 | 7 | import it.cosenonjaviste.testableandroidapps.model.Post; 8 | import it.cosenonjaviste.testableandroidapps.model.PostResponse; 9 | import it.cosenonjaviste.testableandroidapps.model.WordPressService; 10 | import retrofit.RestAdapter; 11 | import retrofit.converter.GsonConverter; 12 | 13 | public class PostBatch { 14 | 15 | public void execute() { 16 | PostResponse postResponse = createService().listPosts(); 17 | EmailSender emailSender = new EmailSender(); 18 | 19 | List posts = postResponse.getPosts(); 20 | for (Post post : posts) { 21 | emailSender.sendEmail(post); 22 | } 23 | } 24 | 25 | private static WordPressService createService() { 26 | //... 27 | RestAdapter restAdapter = new RestAdapter.Builder() 28 | .setEndpoint("http://www.cosenonjaviste.it/") 29 | .setConverter(new GsonConverter(new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create())) 30 | .build(); 31 | return restAdapter.create(WordPressService.class); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /dependencyinjection/src/test/java/it/cosenonjaviste/testableandroidapps/v2/MockitoPostsBatchTest2.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v2; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.mockito.Mock; 7 | import org.mockito.runners.MockitoJUnitRunner; 8 | 9 | import it.cosenonjaviste.testableandroidapps.model.Post; 10 | import it.cosenonjaviste.testableandroidapps.model.PostResponse; 11 | import it.cosenonjaviste.testableandroidapps.model.WordPressService; 12 | 13 | import static org.mockito.Matchers.any; 14 | import static org.mockito.Mockito.times; 15 | import static org.mockito.Mockito.verify; 16 | import static org.mockito.Mockito.when; 17 | 18 | @RunWith(MockitoJUnitRunner.class) 19 | public class MockitoPostsBatchTest2 { 20 | 21 | @Mock WordPressService service; 22 | 23 | @Mock EmailSender sender; 24 | 25 | private PostBatch postBatch; 26 | 27 | @Before public void init() { 28 | postBatch = new PostBatch(service, sender); 29 | } 30 | 31 | @Test 32 | public void testExecute() { 33 | when(service.listPosts()) 34 | .thenReturn(new PostResponse(new Post(), new Post(), new Post())); 35 | 36 | postBatch.execute(); 37 | 38 | verify(sender, times(3)).sendEmail(any(Post.class)); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /dependencyinjection/src/test/java/it/cosenonjaviste/testableandroidapps/v2/MockitoPostBatchTest.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v2; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | import org.mockito.Mockito; 6 | 7 | import it.cosenonjaviste.testableandroidapps.model.Post; 8 | import it.cosenonjaviste.testableandroidapps.model.PostResponse; 9 | import it.cosenonjaviste.testableandroidapps.model.WordPressService; 10 | 11 | import static org.mockito.Matchers.any; 12 | import static org.mockito.Mockito.times; 13 | import static org.mockito.Mockito.verify; 14 | import static org.mockito.Mockito.when; 15 | 16 | public class MockitoPostBatchTest { 17 | 18 | private WordPressService service; 19 | 20 | private EmailSender emailSender; 21 | 22 | private PostBatch postBatch; 23 | 24 | @Before public void init() { 25 | emailSender = Mockito.mock(EmailSender.class); 26 | service = Mockito.mock(WordPressService.class); 27 | postBatch = new PostBatch(service, emailSender); 28 | } 29 | 30 | @Test 31 | public void testExecute() { 32 | when(service.listPosts()) 33 | .thenReturn(new PostResponse(new Post(), new Post(), new Post())); 34 | 35 | postBatch.execute(); 36 | 37 | verify(emailSender, times(3)).sendEmail(any(Post.class)); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/test/java/it/cosenonjaviste/testableandroidapps/JsonParsingTest.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.GsonBuilder; 5 | 6 | import org.junit.Test; 7 | 8 | import java.io.IOException; 9 | import java.util.List; 10 | 11 | import it.cosenonjaviste.testableandroidapps.model.Post; 12 | import it.cosenonjaviste.testableandroidapps.model.PostResponse; 13 | import it.cosenonjaviste.testableandroidapps.utils.FileUtils; 14 | 15 | import static org.junit.Assert.assertEquals; 16 | import static org.junit.Assert.assertNotNull; 17 | 18 | public class JsonParsingTest { 19 | 20 | private Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create(); 21 | 22 | @Test public void parsePostsJson() throws IOException { 23 | PostResponse postResponse = gson.fromJson(FileUtils.readFile("post_response.json"), PostResponse.class); 24 | List posts = postResponse.getPosts(); 25 | assertEquals(2, posts.size()); 26 | Post post = posts.get(0); 27 | assertEquals(12046, post.getId()); 28 | assertNotNull(post.getDate()); 29 | assertNotNull(post.getTitle()); 30 | assertNotNull(post.getUrl()); 31 | assertNotNull(post.getAuthor()); 32 | assertEquals(33, post.getAuthor().getId()); 33 | assertNotNull(post.getAuthor().getName()); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /dependencyinjection/src/test/java/it/cosenonjaviste/testableandroidapps/v5/PostBatchNoDaggerTest.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v5; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.mockito.Mock; 7 | import org.mockito.runners.MockitoJUnitRunner; 8 | 9 | import java.util.concurrent.Executor; 10 | 11 | import it.cosenonjaviste.testableandroidapps.model.Post; 12 | import it.cosenonjaviste.testableandroidapps.model.PostResponse; 13 | import it.cosenonjaviste.testableandroidapps.model.WordPressService; 14 | 15 | import static org.mockito.Matchers.any; 16 | import static org.mockito.Mockito.times; 17 | import static org.mockito.Mockito.verify; 18 | import static org.mockito.Mockito.when; 19 | 20 | @RunWith(MockitoJUnitRunner.class) 21 | public class PostBatchNoDaggerTest { 22 | 23 | @Mock WordPressService service; 24 | 25 | @Mock EmailSender sender; 26 | 27 | private PostBatch postBatch; 28 | 29 | @Before 30 | public void setUp() { 31 | postBatch = new PostBatch(service, sender, new Executor() { 32 | @Override public void execute(Runnable command) { 33 | command.run(); 34 | } 35 | }); 36 | } 37 | 38 | @Test 39 | public void testExecute() { 40 | when(service.listPosts()) 41 | .thenReturn(new PostResponse(new Post(), new Post(), new Post())); 42 | 43 | postBatch.execute(); 44 | 45 | verify(sender, times(3)).sendEmail(any(Post.class)); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/test/java/it/cosenonjaviste/testableandroidapps/v5/SharePresenterTest.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v5; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.mockito.InjectMocks; 6 | import org.mockito.Mock; 7 | import org.mockito.runners.MockitoJUnitRunner; 8 | 9 | import it.cosenonjaviste.testableandroidapps.ShareExecutor; 10 | 11 | import static org.junit.Assert.assertTrue; 12 | import static org.mockito.Matchers.anyString; 13 | import static org.mockito.Matchers.eq; 14 | import static org.mockito.Mockito.never; 15 | import static org.mockito.Mockito.verify; 16 | 17 | @RunWith(MockitoJUnitRunner.class) 18 | public class SharePresenterTest { 19 | 20 | @Mock ShareExecutor shareExecutor; 21 | 22 | @Mock ShareActivity view; 23 | 24 | @InjectMocks SharePresenter sharePresenter; 25 | 26 | @Test 27 | public void testValidationOk() { 28 | ShareModel model = new ShareModel(); 29 | sharePresenter.init(view, model); 30 | 31 | sharePresenter.share("title", "body"); 32 | 33 | verify(shareExecutor).startSendActivity(eq("title"), eq("body")); 34 | } 35 | 36 | @Test 37 | public void testValidationError() { 38 | ShareModel model = new ShareModel(); 39 | sharePresenter.init(view, model); 40 | 41 | sharePresenter.share("", "body"); 42 | 43 | assertTrue(model.getTitleError() != 0); 44 | assertTrue(model.getBodyError() == 0); 45 | 46 | verify(shareExecutor, never()).startSendActivity(anyString(), anyString()); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/test/java/it/cosenonjaviste/testableandroidapps/v6/SharePresenterTest.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v6; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.mockito.InjectMocks; 6 | import org.mockito.Mock; 7 | import org.mockito.runners.MockitoJUnitRunner; 8 | 9 | import it.cosenonjaviste.testableandroidapps.ShareExecutor; 10 | 11 | import static org.junit.Assert.assertTrue; 12 | import static org.mockito.Matchers.anyString; 13 | import static org.mockito.Matchers.eq; 14 | import static org.mockito.Mockito.never; 15 | import static org.mockito.Mockito.verify; 16 | 17 | @RunWith(MockitoJUnitRunner.class) 18 | public class SharePresenterTest { 19 | 20 | @Mock ShareExecutor shareExecutor; 21 | 22 | @Mock ShareActivity view; 23 | 24 | @InjectMocks SharePresenter sharePresenter; 25 | 26 | @Test 27 | public void testValidationOk() { 28 | ShareModel model = new ShareModel(); 29 | sharePresenter.init(view, model); 30 | 31 | sharePresenter.share("title", "body"); 32 | 33 | verify(shareExecutor).startSendActivity(eq("title"), eq("body")); 34 | } 35 | 36 | @Test 37 | public void testValidationError() { 38 | ShareModel model = new ShareModel(); 39 | sharePresenter.init(view, model); 40 | 41 | sharePresenter.share("", "body"); 42 | 43 | assertTrue(model.getTitleError() != 0); 44 | assertTrue(model.getBodyError() == 0); 45 | 46 | verify(shareExecutor, never()).startSendActivity(anyString(), anyString()); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/test/java/it/cosenonjaviste/testableandroidapps/v7/SharePresenterTest.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v7; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.mockito.InjectMocks; 6 | import org.mockito.Mock; 7 | import org.mockito.runners.MockitoJUnitRunner; 8 | 9 | import it.cosenonjaviste.testableandroidapps.ShareExecutor; 10 | 11 | import static org.junit.Assert.assertTrue; 12 | import static org.mockito.Matchers.anyString; 13 | import static org.mockito.Matchers.eq; 14 | import static org.mockito.Mockito.never; 15 | import static org.mockito.Mockito.verify; 16 | 17 | @RunWith(MockitoJUnitRunner.class) 18 | public class SharePresenterTest { 19 | 20 | @Mock ShareExecutor shareExecutor; 21 | 22 | @Mock ShareActivity view; 23 | 24 | @InjectMocks SharePresenter sharePresenter; 25 | 26 | @Test 27 | public void testValidationOk() { 28 | ShareModel model = new ShareModel(); 29 | sharePresenter.init(view, model); 30 | 31 | sharePresenter.share("title", "body"); 32 | 33 | verify(shareExecutor).startSendActivity(eq("title"), eq("body")); 34 | } 35 | 36 | @Test 37 | public void testValidationError() { 38 | ShareModel model = new ShareModel(); 39 | sharePresenter.init(view, model); 40 | 41 | sharePresenter.share("", "body"); 42 | 43 | assertTrue(model.getTitleError() != 0); 44 | assertTrue(model.getBodyError() == 0); 45 | 46 | verify(shareExecutor, never()).startSendActivity(anyString(), anyString()); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/v10/PostListActivity.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v10; 2 | 3 | import android.os.Bundle; 4 | import android.widget.ListView; 5 | 6 | import java.util.List; 7 | 8 | import it.cosenonjaviste.testableandroidapps.ApplicationComponent; 9 | import it.cosenonjaviste.testableandroidapps.CnjApplication; 10 | import it.cosenonjaviste.testableandroidapps.PostAdapter; 11 | import it.cosenonjaviste.testableandroidapps.R; 12 | import it.cosenonjaviste.testableandroidapps.model.Post; 13 | import it.cosenonjaviste.testableandroidapps.mvplib.BaseActivity; 14 | import it.cosenonjaviste.testableandroidapps.mvplib.Presenter; 15 | 16 | 17 | public class PostListActivity extends BaseActivity { 18 | 19 | private PostAdapter adapter; 20 | 21 | @Override 22 | protected void onCreate(Bundle savedInstanceState) { 23 | super.onCreate(savedInstanceState); 24 | 25 | adapter = new PostAdapter(getLayoutInflater()); 26 | ((ListView) findViewById(R.id.list)).setAdapter(adapter); 27 | } 28 | 29 | @Override protected Presenter createPresenter() { 30 | ApplicationComponent component = ((CnjApplication) getApplicationContext()).getComponent(); 31 | return component.getPostListPresenterV10(); 32 | } 33 | 34 | @Override protected int getLayoutId() { 35 | return R.layout.activity_main; 36 | } 37 | 38 | public void updateItems(List items) { 39 | adapter.setItems(items); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/v5/SharePresenter.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v5; 2 | 3 | import javax.inject.Inject; 4 | 5 | import it.cosenonjaviste.testableandroidapps.R; 6 | import it.cosenonjaviste.testableandroidapps.ShareExecutor; 7 | 8 | public class SharePresenter { 9 | 10 | private ShareActivity view; 11 | 12 | private ShareModel model; 13 | 14 | private ShareExecutor shareExecutor; 15 | 16 | @Inject public SharePresenter(ShareExecutor shareExecutor) { 17 | this.shareExecutor = shareExecutor; 18 | } 19 | 20 | public void init(ShareActivity view, ShareModel model) { 21 | this.view = view; 22 | this.model = model; 23 | view.updateUi(model); 24 | } 25 | 26 | public ShareModel getModel() { 27 | return model; 28 | } 29 | 30 | public void updateModel(String title, String body) { 31 | model.setTitle(title); 32 | model.setBody(body); 33 | } 34 | 35 | public void validateFields(String title, String body) { 36 | updateModel(title, body); 37 | model.setTitleError(model.getTitle().isEmpty() ? R.string.mandatory_field : 0); 38 | model.setBodyError(model.getBody().isEmpty() ? R.string.mandatory_field : 0); 39 | view.updateUi(model); 40 | } 41 | 42 | public void share(String title, String body) { 43 | validateFields(title, body); 44 | if (model.getTitleError() == 0 && model.getBodyError() == 0) { 45 | shareExecutor.startSendActivity(title, body); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/v6/SharePresenter.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v6; 2 | 3 | import javax.inject.Inject; 4 | 5 | import it.cosenonjaviste.testableandroidapps.R; 6 | import it.cosenonjaviste.testableandroidapps.ShareExecutor; 7 | 8 | public class SharePresenter { 9 | 10 | private ShareActivity view; 11 | 12 | private ShareModel model; 13 | 14 | private ShareExecutor shareExecutor; 15 | 16 | @Inject public SharePresenter(ShareExecutor shareExecutor) { 17 | this.shareExecutor = shareExecutor; 18 | } 19 | 20 | public void init(ShareActivity view, ShareModel model) { 21 | this.view = view; 22 | this.model = model; 23 | view.updateUi(model); 24 | } 25 | 26 | public ShareModel getModel() { 27 | return model; 28 | } 29 | 30 | public void updateModel(String title, String body) { 31 | model.setTitle(title); 32 | model.setBody(body); 33 | } 34 | 35 | public void validateFields(String title, String body) { 36 | updateModel(title, body); 37 | model.setTitleError(model.getTitle().isEmpty() ? R.string.mandatory_field : 0); 38 | model.setBodyError(model.getBody().isEmpty() ? R.string.mandatory_field : 0); 39 | view.updateUi(model); 40 | } 41 | 42 | public void share(String title, String body) { 43 | validateFields(title, body); 44 | if (model.getTitleError() == 0 && model.getBodyError() == 0) { 45 | shareExecutor.startSendActivity(title, body); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/v7/SharePresenter.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v7; 2 | 3 | import javax.inject.Inject; 4 | 5 | import it.cosenonjaviste.testableandroidapps.R; 6 | import it.cosenonjaviste.testableandroidapps.ShareExecutor; 7 | 8 | public class SharePresenter { 9 | 10 | private ShareActivity view; 11 | 12 | private ShareModel model; 13 | 14 | private ShareExecutor shareExecutor; 15 | 16 | @Inject public SharePresenter(ShareExecutor shareExecutor) { 17 | this.shareExecutor = shareExecutor; 18 | } 19 | 20 | public void init(ShareActivity view, ShareModel model) { 21 | this.view = view; 22 | this.model = model; 23 | view.updateUi(model); 24 | } 25 | 26 | public ShareModel getModel() { 27 | return model; 28 | } 29 | 30 | public void updateModel(String title, String body) { 31 | model.setTitle(title); 32 | model.setBody(body); 33 | } 34 | 35 | public void validateFields(String title, String body) { 36 | updateModel(title, body); 37 | model.setTitleError(model.getTitle().isEmpty() ? R.string.mandatory_field : 0); 38 | model.setBodyError(model.getBody().isEmpty() ? R.string.mandatory_field : 0); 39 | view.updateUi(model); 40 | } 41 | 42 | public void share(String title, String body) { 43 | validateFields(title, body); 44 | if (model.getTitleError() == 0 && model.getBodyError() == 0) { 45 | shareExecutor.startSendActivity(title, body); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/ApplicationModule.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps; 2 | 3 | import android.app.Application; 4 | 5 | import com.google.gson.GsonBuilder; 6 | 7 | import javax.inject.Singleton; 8 | 9 | import dagger.Module; 10 | import dagger.Provides; 11 | import it.cosenonjaviste.testableandroidapps.model.WordPressService; 12 | import retrofit.RestAdapter; 13 | import retrofit.converter.GsonConverter; 14 | import rx.android.schedulers.AndroidSchedulers; 15 | import rx.schedulers.Schedulers; 16 | 17 | @Module 18 | public class ApplicationModule { 19 | private Application application; 20 | 21 | public ApplicationModule(Application application) { 22 | this.application = application; 23 | } 24 | 25 | @Provides @Singleton ShareExecutor provideShareExecutor() { 26 | return new ShareExecutor(application); 27 | } 28 | 29 | @Provides @Singleton WordPressService providesWordPressService() { 30 | RestAdapter restAdapter = new RestAdapter.Builder() 31 | .setEndpoint("http://www.cosenonjaviste.it/") 32 | .setConverter(new GsonConverter(new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create())) 33 | .build(); 34 | if (BuildConfig.DEBUG) { 35 | restAdapter.setLogLevel(RestAdapter.LogLevel.FULL); 36 | } 37 | return restAdapter.create(WordPressService.class); 38 | } 39 | 40 | @Provides @Singleton SchedulerManager providesSchedulerManager() { 41 | return new SchedulerManager(Schedulers.io(), AndroidSchedulers.mainThread()); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/src/androidTest/java/it/cosenonjaviste/testableandroidapps/v2/PostListActivityTest.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.v2; 2 | 3 | import android.support.test.rule.ActivityTestRule; 4 | 5 | import org.junit.Rule; 6 | import org.junit.Test; 7 | 8 | import java.io.IOException; 9 | 10 | import it.cosenonjaviste.testableandroidapps.PostCreator; 11 | import it.cosenonjaviste.testableandroidapps.R; 12 | import rx.Observable; 13 | 14 | import static android.support.test.espresso.Espresso.onView; 15 | import static android.support.test.espresso.assertion.ViewAssertions.matches; 16 | import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; 17 | import static android.support.test.espresso.matcher.ViewMatchers.withId; 18 | import static android.support.test.espresso.matcher.ViewMatchers.withText; 19 | 20 | public class PostListActivityTest { 21 | @Rule public final ActivityTestRule rule = new ActivityTestRule<>(TestablePostListActivity.class, false, false); 22 | 23 | @Test public void showListActivity() { 24 | TestablePostListActivity.result = Observable.just( 25 | PostCreator.createPost(1), 26 | PostCreator.createPost(2), 27 | PostCreator.createPost(3) 28 | ).toList(); 29 | 30 | rule.launchActivity(null); 31 | 32 | onView(withText("title 1")).check(matches(isDisplayed())); 33 | } 34 | 35 | @Test public void checkErrorLayoutDisplayed() { 36 | TestablePostListActivity.result = Observable.error(new IOException()); 37 | 38 | rule.launchActivity(null); 39 | 40 | onView(withId(R.id.error_layout)).check(matches(isDisplayed())); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/it/cosenonjaviste/testableandroidapps/mvplib/MvpContext.java: -------------------------------------------------------------------------------- 1 | package it.cosenonjaviste.testableandroidapps.mvplib; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | 6 | import org.parceler.Parcels; 7 | 8 | import it.cosenonjaviste.testableandroidapps.RetainedFragment; 9 | 10 | public class MvpContext { 11 | 12 | public static final String MODEL = "model"; 13 | 14 | protected M model; 15 | 16 | protected V view; 17 | 18 | protected Presenter presenter; 19 | 20 | public MvpContext(V view, Bundle state, RetainedFragment> retainedFragment) { 21 | this.presenter = retainedFragment.get(); 22 | 23 | if (state != null) { 24 | model = Parcels.unwrap(state.getParcelable(MODEL)); 25 | } 26 | if (model == null) { 27 | model = presenter.createDefaultModel(); 28 | } 29 | 30 | retainedFragment.setOnDestroy(c -> presenter.destroy()); 31 | 32 | this.view = view; 33 | } 34 | 35 | protected MvpContext() { 36 | } 37 | 38 | public static void populateIntent(Intent intent, Object model) { 39 | intent.putExtra(MODEL, Parcels.wrap(model)); 40 | } 41 | 42 | public M getModel() { 43 | return model; 44 | } 45 | 46 | public V getView() { 47 | return view; 48 | } 49 | 50 | public void saveState(Bundle outState) { 51 | outState.putParcelable(MODEL, Parcels.wrap(model)); 52 | } 53 | 54 | public void resume() { 55 | presenter.resume(this); 56 | } 57 | 58 | public void pause() { 59 | presenter.pause(); 60 | } 61 | 62 | public Presenter getPresenter() { 63 | return presenter; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_detail.xml: -------------------------------------------------------------------------------- 1 | 11 | 12 | 16 | 17 | 21 | 22 | 27 | 28 | 33 | 34 |