Repository: patrykpoborca/CleanArchitecture
Branch: master
Commit: d8437d80fe2e
Files: 102
Total size: 135.7 KB
Directory structure:
gitextract_n6u9vjvq/
├── .gitignore
├── .idea/
│ ├── .name
│ ├── compiler.xml
│ ├── copyright/
│ │ └── profiles_settings.xml
│ ├── encodings.xml
│ ├── gradle.xml
│ ├── misc.xml
│ ├── modules.xml
│ ├── runConfigurations.xml
│ └── vcs.xml
├── README.md
├── app/
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src/
│ ├── androidTest/
│ │ └── java/
│ │ └── io/
│ │ └── patrykpoborca/
│ │ └── cleanarchitecture/
│ │ ├── TestHelper.java
│ │ ├── dagger/
│ │ │ ├── TestClassInjector.java
│ │ │ └── mockmodules/
│ │ │ ├── MockLocalModule.java
│ │ │ ├── MockNetworkModule.java
│ │ │ └── MockTestModule.java
│ │ ├── mockimpl/
│ │ │ ├── MockLocalDataCache.java
│ │ │ ├── MockMVPCIPview.java
│ │ │ ├── MockOkHTTP.java
│ │ │ ├── MockRetrofit.java
│ │ │ ├── MockTweeterActivityPview.java
│ │ │ └── MockTweeterApi.java
│ │ └── tests/
│ │ ├── MVPCITest.java
│ │ ├── MVPTest.java
│ │ ├── MVVMTest.java
│ │ └── PlainTweeterTest.java
│ ├── main/
│ │ ├── AndroidManifest.xml
│ │ ├── java/
│ │ │ └── io/
│ │ │ └── patrykpoborca/
│ │ │ └── cleanarchitecture/
│ │ │ ├── CleanArchitectureApplication.java
│ │ │ ├── dagger/
│ │ │ │ ├── components/
│ │ │ │ │ ├── ActivityInjectorComponent.java
│ │ │ │ │ ├── ApplicationComponent.java
│ │ │ │ │ └── BaseComponent.java
│ │ │ │ ├── interactors/
│ │ │ │ │ ├── NetworkInteractor.java
│ │ │ │ │ └── base/
│ │ │ │ │ └── BaseInteractor.java
│ │ │ │ ├── modules/
│ │ │ │ │ ├── ApplicationModule.java
│ │ │ │ │ ├── InteractorModule.java
│ │ │ │ │ ├── LocalModule.java
│ │ │ │ │ ├── NetworkModule.java
│ │ │ │ │ ├── PresenterModule.java
│ │ │ │ │ └── ThreadingModule.java
│ │ │ │ └── scopes/
│ │ │ │ ├── ActivityScope.java
│ │ │ │ ├── ApplicationScope.java
│ │ │ │ └── ExposedAPIScope.java
│ │ │ ├── localdata/
│ │ │ │ └── LocalDataCache.java
│ │ │ ├── network/
│ │ │ │ ├── TweeterApi.java
│ │ │ │ └── base/
│ │ │ │ ├── OKHttp.java
│ │ │ │ └── Retrofit.java
│ │ │ ├── ui/
│ │ │ │ ├── BaseCleanArchitectureActivity.java
│ │ │ │ ├── MVP/
│ │ │ │ │ ├── TweeterActivityMVP.java
│ │ │ │ │ ├── TweeterMVPPresenterImpl.java
│ │ │ │ │ ├── base/
│ │ │ │ │ │ ├── BasePresenterActivity.java
│ │ │ │ │ │ └── Interfaces/
│ │ │ │ │ │ ├── PView.java
│ │ │ │ │ │ └── Presenter.java
│ │ │ │ │ └── interfaces/
│ │ │ │ │ ├── TweeterMVPPView.java
│ │ │ │ │ └── TweeterMVPPresenter.java
│ │ │ │ ├── MVPCI/
│ │ │ │ │ ├── TweeterActivityMVPCI.java
│ │ │ │ │ ├── TweeterMVPCIPresenter.java
│ │ │ │ │ ├── base/
│ │ │ │ │ │ ├── BasePresenterActivityMVPCI.java
│ │ │ │ │ │ └── BasePresenterMVPCI.java
│ │ │ │ │ ├── interfaces/
│ │ │ │ │ │ └── TweeterActivityMVPCIPview.java
│ │ │ │ │ └── models/
│ │ │ │ │ └── UserProfile.java
│ │ │ │ ├── MVVM/
│ │ │ │ │ ├── MainViewmodel.java
│ │ │ │ │ ├── TweeterActivityMVVM.java
│ │ │ │ │ └── base/
│ │ │ │ │ ├── BaseViewModel.java
│ │ │ │ │ └── BaseViewModelActivity.java
│ │ │ │ ├── PlainTweeterActivity.java
│ │ │ │ └── RouterActivity.java
│ │ │ └── util/
│ │ │ ├── Constants.java
│ │ │ ├── LoadingFragment.java
│ │ │ └── utility.java
│ │ └── res/
│ │ ├── layout/
│ │ │ ├── activity_main.xml
│ │ │ ├── activity_router.xml
│ │ │ └── fragment_progress.xml
│ │ ├── menu/
│ │ │ └── menu_main.xml
│ │ ├── values/
│ │ │ ├── dimens.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ └── values-w820dp/
│ │ └── dimens.xml
│ └── test/
│ └── java/
│ ├── dagger/
│ │ ├── TestClassInjector.java
│ │ └── mockmodules/
│ │ ├── MockLocalModule.java
│ │ ├── MockNetworkModule.java
│ │ ├── MockTestModule.java
│ │ └── MockThreadingModule.java
│ ├── helper/
│ │ └── TestHelper.java
│ ├── mockimpl/
│ │ ├── MockLocalDataCache.java
│ │ ├── MockMVPCIPview.java
│ │ ├── MockOkHTTP.java
│ │ ├── MockRetrofit.java
│ │ ├── MockTweeterActivityPview.java
│ │ └── MockTweeterApi.java
│ └── tests/
│ ├── MVPCITest.java
│ ├── MVPTest.java
│ └── MVVMTest.java
├── build.gradle
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
.gradle
*.iml
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
================================================
FILE: .idea/.name
================================================
CleanArchitecture
================================================
FILE: .idea/compiler.xml
================================================
================================================
FILE: .idea/copyright/profiles_settings.xml
================================================
================================================
FILE: .idea/encodings.xml
================================================
================================================
FILE: .idea/gradle.xml
================================================
================================================
FILE: .idea/misc.xml
================================================
Android Lint
C/C++
Class structureJava
Code maturity issuesJava
Code style issuesJava
Compiler issuesJava
Declaration orderC/C++
Finalization issuesJava
Groovy
Inheritance issuesJava
J2ME issuesJava
Java
Java language level migration aidsJava
JavaBeans issuesJava
Javadoc issuesJava
Numeric issuesJava
OtherGroovy
Performance issuesJava
Probable bugsJava
Security issuesJava
Serialization issuesJava
TestNGJava
Threading issuesJava
Type checksC/C++
Verbose or redundant code constructsJava
Android
1.7
================================================
FILE: .idea/modules.xml
================================================
================================================
FILE: .idea/runConfigurations.xml
================================================
================================================
FILE: .idea/vcs.xml
================================================
================================================
FILE: README.md
================================================
# CleanArchitecture
Thanks for checking out my github repo. There's not much to say in this readme since I wrote two articles about this repo here:
[Article 1 - Dagger 2 introduction](https://medium.com/@patrykpoborca/making-a-best-practice-app-4-dagger-2-267ec5f6c89a)
[Article 2 - Clean Architecture and Testing in JUnit and AndroidJunit with Espresso](https://medium.com/@patrykpoborca/making-a-best-practice-app-5-clean-architecture-testing-84a1672dd000)
To sum, the articles and this repo go into how to utilize Dagger 2 in order to setup and start your project. How to properly implement some variant of an Architecture so that your app is scalable and testable.
Finally we go over how to actually implement those tests. I have similar tests in both POJO (Plain old java object) Junit and Android Junit which utilizes Some mockito.
I also show how annoying/and or obnoxious it is to test imporoperly architected applications by actually testing my "PlainTweeterActivity"
I hope you learn something from this, if you have any questions or issues feel free to start an issue here or [tweet me here](https://twitter.com/patrykpoborca)
Also if you want to see the talk about Dagger 2 I did here [it is](https://www.youtube.com/watch?v=JNbz_rgdQ10)
Thanks!
================================================
FILE: app/.gitignore
================================================
/build
================================================
FILE: app/build.gradle
================================================
apply plugin: 'me.tatarka.retrolambda'
apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'
//apply plugin: "net.ltgt.apt"
android {
compileSdkVersion 22
buildToolsVersion '23.0.2'
defaultConfig {
applicationId "io.patrykpoborca.cleanarchitecture"
minSdkVersion 22
targetSdkVersion 22
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
compileOptions {
encoding "UTF-8"
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
dependencies {
apt 'com.google.dagger:dagger-compiler:2.0'
testProvided 'com.google.dagger:dagger-compiler:2.0'
//needed to resolve compilation errors, thanks to tutplus.org for finding the dependency
// http://stackoverflow.com/questions/27036933/how-to-set-up-dagger-dependency-injection-from-scratch-in-android-project
//test compiles
androidTestApt 'com.google.dagger:dagger-compiler:2.0'
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.android.support:appcompat-v7:22.2.0'
compile 'com.google.dagger:dagger:2.0'
provided 'org.glassfish:javax.annotation:10.0-b28'
compile 'io.reactivex:rxandroid:0.25.0'
compile 'com.jakewharton:butterknife:7.0.1'
androidTestCompile 'com.google.dagger:dagger:2.0'
testCompile 'com.google.dagger:dagger:2.0'
testCompile 'junit:junit:4.12'
androidTestCompile 'com.android.support.test:runner:0.3'
// Set this dependency to use JUnit 4 rules
androidTestCompile 'com.android.support.test:rules:0.3'
androidTestCompile 'org.mockito:mockito-core:1.+'
androidTestCompile('com.android.support.test:runner:0.3') {
exclude group: 'com.android.support', module: 'support-annotations'
}
androidTestCompile 'com.google.dexmaker:dexmaker:1.2'
androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'
androidTestCompile 'com.android.support.test:runner:0.3'
androidTestCompile 'com.android.support.test:rules:0.3'
androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2'
}
}
================================================
FILE: app/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in C:\Users\Patryk\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
================================================
FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/TestHelper.java
================================================
package io.patrykpoborca.cleanarchitecture;
import android.app.Application;
import io.patrykpoborca.cleanarchitecture.dagger.DaggerTestClassInjector;
import io.patrykpoborca.cleanarchitecture.dagger.TestClassInjector;
import io.patrykpoborca.cleanarchitecture.dagger.components.ApplicationComponent;
import io.patrykpoborca.cleanarchitecture.dagger.components.BaseComponent;
import io.patrykpoborca.cleanarchitecture.dagger.components.DaggerApplicationComponent;
import io.patrykpoborca.cleanarchitecture.dagger.components.DaggerBaseComponent;
import io.patrykpoborca.cleanarchitecture.dagger.mockmodules.MockLocalModule;
import io.patrykpoborca.cleanarchitecture.dagger.mockmodules.MockNetworkModule;
import io.patrykpoborca.cleanarchitecture.dagger.modules.ApplicationModule;
public class TestHelper {
private static ApplicationComponent sApplicationComponent;
private static BaseComponent sBaseComponent;
private static TestClassInjector sTestClassInjector;
public static ApplicationComponent getApplicationComponent(){
if(sApplicationComponent == null)
{
sApplicationComponent = DaggerApplicationComponent.builder()
.applicationModule(new ApplicationModule(new Application()))
.build();
}
return sApplicationComponent;
}
public static BaseComponent getBaseComponent(){
if(sBaseComponent == null){
sBaseComponent = DaggerBaseComponent.builder()
.applicationComponent(getApplicationComponent())
.localModule(new MockLocalModule())
.networkModule(new MockNetworkModule())
.build();
}
return sBaseComponent;
}
public static TestClassInjector getTestClassInjector(){
if(sTestClassInjector == null){
sTestClassInjector = DaggerTestClassInjector.builder()
.baseComponent(getBaseComponent())
.build();
}
return sTestClassInjector;
}
public static void waitFor(IWaitingCallback callback){
waitFor(10, callback);
}
public static void waitFor(int maxCycles, IWaitingCallback callback){
while(true){
maxCycles --;
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(callback.checkCondition()){
break;
}
if(maxCycles <= 0){
break;
}
}
}
public static interface IWaitingCallback{
/**
*
* @return true if condition is met, false if we should keep waiting
*/
public boolean checkCondition();
}
}
================================================
FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/dagger/TestClassInjector.java
================================================
package io.patrykpoborca.cleanarchitecture.dagger;
import dagger.Component;
import io.patrykpoborca.cleanarchitecture.dagger.mockmodules.MockTestModule;
import io.patrykpoborca.cleanarchitecture.tests.MVPCITest;
import io.patrykpoborca.cleanarchitecture.tests.MVPTest;
import io.patrykpoborca.cleanarchitecture.tests.MVVMTest;
import io.patrykpoborca.cleanarchitecture.dagger.components.BaseComponent;
import io.patrykpoborca.cleanarchitecture.dagger.scopes.ActivityScope;
@ActivityScope
@Component(dependencies = BaseComponent.class, modules = MockTestModule.class)
public interface TestClassInjector {
void inject(MVVMTest test);
void inject(MVPTest MVPTest);
void inject(MVPCITest mvpciTest);
}
================================================
FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/dagger/mockmodules/MockLocalModule.java
================================================
package io.patrykpoborca.cleanarchitecture.dagger.mockmodules;
import android.app.Application;
import io.patrykpoborca.cleanarchitecture.dagger.modules.LocalModule;
import io.patrykpoborca.cleanarchitecture.localdata.LocalDataCache;
import io.patrykpoborca.cleanarchitecture.mockimpl.MockLocalDataCache;
public class MockLocalModule extends LocalModule{
@Override
protected LocalDataCache providesDataCache(Application application) {
return new MockLocalDataCache(application);
}
}
================================================
FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/dagger/mockmodules/MockNetworkModule.java
================================================
package io.patrykpoborca.cleanarchitecture.dagger.mockmodules;
import javax.inject.Named;
import io.patrykpoborca.cleanarchitecture.dagger.modules.NetworkModule;
import io.patrykpoborca.cleanarchitecture.mockimpl.MockOkHTTP;
import io.patrykpoborca.cleanarchitecture.mockimpl.MockRetrofit;
import io.patrykpoborca.cleanarchitecture.network.base.OKHttp;
import io.patrykpoborca.cleanarchitecture.network.base.Retrofit;
import io.patrykpoborca.cleanarchitecture.util.Constants;
import rx.Scheduler;
public class MockNetworkModule extends NetworkModule {
@Override
protected OKHttp providesOkHTTP() {
return new MockOkHTTP();
}
@Override
protected Retrofit providesRetrofit(OKHttp okHttp, @Named(Constants.MAIN_THREAD)Scheduler mainThread) {
return new MockRetrofit(okHttp, mainThread);
}
}
================================================
FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/dagger/mockmodules/MockTestModule.java
================================================
package io.patrykpoborca.cleanarchitecture.dagger.mockmodules;
import javax.inject.Named;
import dagger.Module;
import dagger.Provides;
import io.patrykpoborca.cleanarchitecture.dagger.scopes.ActivityScope;
import io.patrykpoborca.cleanarchitecture.localdata.LocalDataCache;
import io.patrykpoborca.cleanarchitecture.mockimpl.MockMVPCIPview;
import io.patrykpoborca.cleanarchitecture.mockimpl.MockTweeterActivityPview;
import io.patrykpoborca.cleanarchitecture.mockimpl.MockTweeterApi;
import io.patrykpoborca.cleanarchitecture.network.TweeterApi;
import io.patrykpoborca.cleanarchitecture.network.base.Retrofit;
import io.patrykpoborca.cleanarchitecture.ui.MVP.TweeterMVPPresenterImpl;
import io.patrykpoborca.cleanarchitecture.ui.MVP.interfaces.TweeterMVPPresenter;
import io.patrykpoborca.cleanarchitecture.util.Constants;
import rx.Scheduler;
@Module
public class MockTestModule {
@Provides
@ActivityScope
TweeterMVPPresenter providesMainPresenter(TweeterApi api, Retrofit retrofit) {
return new TweeterMVPPresenterImpl(api, retrofit);
}
@ActivityScope
@Provides
public MockTweeterActivityPview providesMockMainPview(TweeterMVPPresenter presenter) {
MockTweeterActivityPview mockTweeterActivityPview = new MockTweeterActivityPview();
presenter.registerView(mockTweeterActivityPview);
return mockTweeterActivityPview;
}
@ActivityScope
@Provides
public TweeterApi providesMockTweeter(Retrofit retrofit, LocalDataCache dataCache, @Named(Constants.MAIN_THREAD) Scheduler mainThread) {
return new MockTweeterApi(retrofit, dataCache, mainThread);
}
@ActivityScope
@Provides
public MockMVPCIPview providesMockMVPCCIView(){
return new MockMVPCIPview();
}
}
================================================
FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/mockimpl/MockLocalDataCache.java
================================================
package io.patrykpoborca.cleanarchitecture.mockimpl;
import android.content.Context;
import java.util.List;
import io.patrykpoborca.cleanarchitecture.localdata.LocalDataCache;
import rx.Observable;
public class MockLocalDataCache extends LocalDataCache {
public MockLocalDataCache(Context context) {
super(context);
}
@Override
public void saveTweet(String tweet) {
sPastTweets.add(tweet);
}
@Override
public Observable> fetchRecentTweets() {
return Observable.just(sPastTweets)
.map(arrayList -> {
List list = arrayList;
return list;
});
}
}
================================================
FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/mockimpl/MockMVPCIPview.java
================================================
package io.patrykpoborca.cleanarchitecture.mockimpl;
import io.patrykpoborca.cleanarchitecture.ui.MVPCI.interfaces.TweeterActivityMVPCIPview;
import io.patrykpoborca.cleanarchitecture.ui.MVPCI.models.UserProfile;
public class MockMVPCIPview implements TweeterActivityMVPCIPview {
public UserProfile loggedInProfile;
public boolean loggedOutCalled = false;
public boolean toggleProgresbarCalled = false;
@Override
public void loggedIn(UserProfile profile) {
this.loggedInProfile = profile;
}
@Override
public void loggedOut() {
loggedOutCalled = true;
}
@Override
public void toggleProgressBar(boolean loading) {
toggleProgresbarCalled = true;
}
@Override
public void displayToast(String toast) {
}
}
================================================
FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/mockimpl/MockOkHTTP.java
================================================
package io.patrykpoborca.cleanarchitecture.mockimpl;
import io.patrykpoborca.cleanarchitecture.network.base.OKHttp;
public class MockOkHTTP extends OKHttp {
@Override
public String rawResponse() {
return "Mocked raw response: ";
}
}
================================================
FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/mockimpl/MockRetrofit.java
================================================
package io.patrykpoborca.cleanarchitecture.mockimpl;
import io.patrykpoborca.cleanarchitecture.network.base.OKHttp;
import io.patrykpoborca.cleanarchitecture.network.base.Retrofit;
import rx.Observable;
import rx.Scheduler;
public class MockRetrofit extends Retrofit {
private static final String MOCK_PARSE = "SomeMockResponse";
public static final String MOCKED_STRING = "MOCKED PAGE:";
public MockRetrofit(OKHttp okHttp, Scheduler mainScheduler) {
super(okHttp, mainScheduler);
}
@Override
public Observable completeRequest() {
return Observable.just(okHttp.rawResponse() + MOCK_PARSE)
.observeOn(mainScheduler);
}
@Override
public Observable fetchSomePage(String url) {
return Observable.just("" + MOCKED_STRING + " " + url + "
")
.observeOn(mainScheduler);
}
}
================================================
FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/mockimpl/MockTweeterActivityPview.java
================================================
package io.patrykpoborca.cleanarchitecture.mockimpl;
import java.util.List;
import io.patrykpoborca.cleanarchitecture.ui.MVP.interfaces.TweeterMVPPView;
public class MockTweeterActivityPview implements TweeterMVPPView {
public String fetchedTweet = null;
public List previousTweets = null;
public boolean setUserButtonTextCalled = false;
public boolean toggleProgressBarCalled = false;
public boolean toggleLoginContainerCalled = false;
public String displayWebpage = null;
public boolean displayToastCalled = false;
@Override
public void displayFetchedTweet(String tweet) {
fetchedTweet = tweet;
}
@Override
public void displayPreviousTweets(List list) {
previousTweets = list;
}
@Override
public void setUserButtonText(String text) {
setUserButtonTextCalled = true;
}
@Override
public void toggleLoginContainer(boolean b) {
toggleLoginContainerCalled = true;
}
@Override
public void displayWebpage(String html) {
displayWebpage = html;
}
@Override
public void toggleProgressBar(boolean loading) {
toggleProgressBarCalled = true;
}
@Override
public void displayToast(String toast) {
displayToastCalled = true;
}
}
================================================
FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/mockimpl/MockTweeterApi.java
================================================
package io.patrykpoborca.cleanarchitecture.mockimpl;
import android.util.Log;
import io.patrykpoborca.cleanarchitecture.localdata.LocalDataCache;
import io.patrykpoborca.cleanarchitecture.network.TweeterApi;
import io.patrykpoborca.cleanarchitecture.network.base.Retrofit;
import io.patrykpoborca.cleanarchitecture.ui.MVPCI.models.UserProfile;
import rx.Observable;
import rx.Scheduler;
public class MockTweeterApi extends TweeterApi{
public MockTweeterApi(Retrofit retrofit, LocalDataCache dataCache, Scheduler mainScheduler) {
super(retrofit, dataCache, mainScheduler);
}
@Override
public Observable login(String username, String password) {
return Observable.just(new UserProfile(username, password));
}
@Override
public Observable