Last active
January 9, 2018 01:08
-
-
Save scottroemeschke/17dbdeb16649cb9ccccf6d65e1043f54 to your computer and use it in GitHub Desktop.
part of conversation : https://www.reddit.com/r/androiddev/comments/7o2d6w/im_done_with_code_tests_rant_inside/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//many ways to slice this up, just an example | |
//syntax may be missing something, been writing Kotlin for a couple years now | |
//also this sort of thing is general a much better API with RxJava but here's a basic implementation. | |
public interface CitiesRepo { | |
//could give an executor here or something to let caller dictate threading/scheduling context | |
Cancelable getCities(AsyncCallback<List<Cities> callback); | |
} | |
//Could just be a class as well. | |
//Just defining as interface because I'm too lazy to implement, but the gist of it is there | |
public interface Cancelable { | |
public boolean isCanceled(); | |
public void cancel(); | |
} | |
//doesn't need to be an interface if you want it to have functionality could be abstract class, etc. | |
interface AsyncCallback<T> { | |
void onSuccess(List<City> cities); | |
void onFailure(Throwable error); | |
} | |
//this can be easily 100% unit tested, | |
//it doesn't need to be an interface because it's super easy to feed it data and see the output. | |
//there's no side effects here (purely input -> output). | |
public class CitiesParser() { | |
List<Cities> parseCities(InputStream citiesInput) throws JsonMalformedException { | |
//blah blah parse this json, throw if the json is messed-up | |
} | |
} | |
interface CitiesFetcher { | |
InputStream getCities() throws IOException; | |
} | |
class CitiesFetcherFromAssets extends CitiesFetcher { | |
private Context appContext; | |
public CitiesFetcherFromAssets(Context appContext) { | |
context = appContext; | |
} | |
@Override | |
InputStream getCities() throws IOException { | |
//blah get assets from context grab the filename for the cities file etc. | |
//you could also have like an assets class that takes a filename and | |
//gives back a string or byte[] and use that, then you can test that with robolectric or integration tests. | |
} | |
} | |
//This can also be 100% unit tested. Make sure it cancels appropriately, returns failure or success when it should. etc. | |
//You can test threading, you can test that it returns an empty list and not a null one if the list from the parser is empty etc. | |
//You can test that it delievers the error in the callback, and never actually throws the exception. etc. | |
class CitiesRepository extends CitiesRepo { | |
private CitiesParser parser; | |
private CitiesFetcher fetcher; | |
public CitiesRepository(CitiesParser parser, CitiesFetcher fetcher) { | |
this.parser = parser; | |
this.fetcher = fetcher; | |
} | |
@Override | |
Cancelable getCities(AsyncCallback<List<Cities> callback) { | |
//get from fetcher, feed that to parser | |
//return back the data in the callback or the error if there is a problem | |
//you could also have caching here if the data never changes, and return the cached data if you've already fetched it once | |
//you can check the cancelable at any time during the process to see if they've requested canceling the work etc. | |
} | |
} | |
//then your viewmodel gets a cityrepo in the constructor as a dependency and interacts with it | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment