I was wondering if it was good practice to subclass the test cases on Android. I mean, I need to test a lot of Parcelable objects and I could create a class like GenerericParcelableAndroidTestCase to test all these objects.
I also have a problem implementing it, I have something like this:
public class GenericParcelableTest extends AndroidTestCase {
private Parcelable p = null;
GenericParcelableTest(Parcelable p) {
this.p = p;
}
public void testDescribeContents() throws Exception {
assertEquals(0, p.describeContents());
}
}
And that:
public class AttachmentTest extends GenericParcelableTest {
public AttachmentTest() {
super(new Attachment());
}
}
Attachment implements Parcelable of course.
It returns me this error:
junit.framework.AssertionFailedError: Class GenericParcelableTest has no public constructor TestCase(String name) or TestCase()
I mean, I know that I created no empty constructor but why would I need one?
And generally, is there some known issues with this approach? If not why is there very few article on this topic on the internet (and actually some say even that it's not a good idea).
I have this conversation quite often when introducing new team members to unit testing. The way I explain it is by stating that your tests are first class citizens of your code base (no pun intended), they are susceptible to the same technical debt as any other part of your code base and have equivalent (maybe more?!) importance as that of the runtime code.
With this mindset, the questions begins to answer itself; if it makes sense from an OO perspective to use inheritance (i.e. your subclass is a insert name of test superclass) then subclass away. However, like any abuse of inheritance ever, be careful...the minute you add a test case that doesn't rely upon that superclass behaviour you may have a code smell.
In this scenario, it's likely (perhaps 90% of the time?) it is a separation of concern issue within the code being placed under test, i.e. the "unit" under test isn't actually (one) unit but has combinatorial behaviour. Refactoring that code to do one thing would be a good way of allowing your super-class test case to live on. However, watch this super class test case like a hawk...the minute you see booleans being added to signatures to "allow that similar but not the same" test case to run under your once unpolluted super class then you have a problem, a tech debt problem that is no different to your runtime code.
At last check AndroidTestCase depends on an Activity context so it's likely best described as an integration test which tend to regularly have boilerplate super-class test behaviour. In this case, try to narrow the focus of your superclass to the use case under test...i.e. extends LoginUseCase or extends LoginScenario to better "bucket" those subclasses in the first instance. This will help guide would be extenders as to whether they should be using it for their non-login scenario. Hopefully, conversation will ensue and tech debt accumulation be avoided!
Regarding your error, in JUnit3 do what #Allen recommends, if moving to JUnit4 with something like Robolectric then explore using Rules as well as #BeforeClass.
Personal note
I have only felt the need to write test super classes for pseudo-unit tests that mock an API end point (akin to MockWebServer if you are familiar with that product) and DAO integration tests whereby an in-memory db is started and torn down over the lifecycle of each test (warning - slow (but useful) tests!)
junit.framework.AssertionFailedError: Class GenericParcelableTest has no public constructor TestCase(String name) or TestCase()
You get this error because JUnit needs to be able to construct an instance of your test class. It only knows how to do this using no-arg, or single string constructors.
Instead of performing initialization in your constructor, you should put it in the setUp() method. This will let you use the default constructor while still initializing the object before the test method is called.
Related
I am great fan of Kotlin and how it allows us to write better code. One of the best features is interface implementation delegation which looks like this:
class A(val someObject:SomeInterface) : SomeInterface by someObject
someObject has to be singleton (object), has to be created using constructor after keyword by (but then you cannot reference to it, or maybe someone has idea how to do it?) or has to be provided in constructor.
In Android messy and bad world we are discouraged to use constructors in fragments and activites due to configuration changes. But how about this:
class MyFragment(val someObject:SomeInterface = SomeObjectImpl()):Fragment,SomeInterface by someObject
I tried to change configuration and event I allowed system to kill my appliction and still, everything is looking ok, my object is creating again and again with my fragment. Is this valid, or am I missing something?
Happy Kotlin everyone!
This is valid. The reason you're discouraged from overloading fragment constructors is that Android can recreate them, and it will use the default one: MyFragment()
But the way Kotlin implements default parameter values behind the scenes is by creating additional constructors. You can decompile your class and see it contains two constructors now, one receiving someObject, and another empty.
From the JVM perspective the empty constructor would look like this:
public A() {
this(new SomeObjectImpl());
}
Calling it will populate your fragment with new instances of implemented classes.
One of the best advantages of using DI is it makes testing a lot easier (What is dependency injection? backs it too). Most of DI frameworks I've worked with on other programming languages (MEF on .NET, Typhoon on Obj-C/Swift, Laravel's IoC Container on PHP, and some others) allows the developer do register dependencies on a single entry point for each component, thus preventing the "creation" of dependency on the object itself.
After I read Dagger 2 documentation, it sounds great the whole "no reflection" business, but I fail to see how it makes testing easier as objects are still kind of creating their own dependencies.
For instance, in the CoffeMaker example:
public class CoffeeApp {
public static void main(String[] args) {
// THIS LINE
CoffeeShop coffeeShop = DaggerCoffeeShop.create();
coffeeShop.maker().brew();
}
}
Even though you're not explicitly calling new, you still have to create your dependency.
Now for a more detailed example, let's go to an Android Example.
If you open up DemoActivity class, you will notice the onCreate implementation goes like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Perform injection so that when this call returns all dependencies will be available for use.
((DemoApplication) getApplication()).component().inject(this);
}
You can clearly see there is no decoupling from the DI component, to the actual code. In summary, you'd need to mock/stub ((DemoApplication) getApplication()).component().inject(this); on a test case (if that's even possible).
Up to this point, I am aware Dagger 2 is pretty popular, so there is got to be something I am not seeing. So how does Dagger 2 makes testing classes easier? How would I mock, let's say a network service class that my Activity depends on? I would like the answer to be as simple as possible as I'm only interested in testing.
Dagger 2 doesn't make testing easier
...beyond encouraging you to inject dependencies in the first place, which naturally makes individual classes more testable.
The last I heard, the Dagger 2 team were still considering potential approaches to improving support for testing - though whatever discussions are going on, they don't seem to be very public.
So how do I test now?
You're correct to point out that classes which want to make explicit use of a Component have a dependency on it. So... inject that dependency! You'll have to inject the Component 'by hand', but that shouldn't be too much trouble.
The official way
Currently, the officially-recommended approach to swapping dependencies for testing is to create a test Component which extends your production one, then have that use custom modules where necessary. Something like this:
public class CoffeeApp {
public static CoffeeShop sCoffeeShop;
public static void main(String[] args) {
if (sCoffeeShop == null) {
sCoffeeShop = DaggerCoffeeShop.create();
}
coffeeShop.maker().brew();
}
}
// Then, in your test code you inject your test Component.
CoffeeApp.sCoffeeShop = DaggerTestCoffeeShop.create();
This approach works well for the things you always want to replace when you are running tests - e.g. Networking code where you want to run against a mock server instead, or IdlingResource implementations of things for running Espresso tests.
The unofficial way
Unfortunately, it the official way can involve a lot of boilerplate code - fine as a one-off, but a real pain if you only want to swap out a single dependency for one particular set of tests.
My favourite hack for this is to simply extend whichever Module has the dependency you want to replace, then override the #Provides method. Like so:
CoffeeApp.sCoffeeShop = DaggerCoffeeShop.builder()
.networkModule(new NetworkModule() {
// Do not add any #Provides or #Scope annotations here or you'll get an error from Dagger at compile time.
#Override
public RequestFactory provideRequestFactory() {
return new MockRequestFactory();
}
})
.build();
Check this gist for a full example.
"allows the developer do register dependencies on a single entry point for
each component" - analogues in Dagger 2 are the Modules and Components where you define the dependencies. The advantage is that you don't define the dependencies directly in your component thus decoupling it so later when writing unit tests you may switch the Dagger 2 component with a test one.
"it sounds great the whole "no reflection" business" - the "no reflection" thing is not the "big deal" about dagger. The "big deal" is the full dependency graph validation at compile time. Others DI frameworks don't have this feature and if you fail to define how some dependency is satisfied you will get an error late at runtime. If the error is located in some rarely used codepath your program may look like it is correct but it will fail at some point in the future.
"Even though you're not explicitly calling new, you still have to create your dependency." - well, you always have to somehow initiate dependency injection. Other DI may "hide"/automate this activity but at the end somewhere building of the graph is performed. For dagger 1&2 this is done at app start. For "normal" apps (as you shown in the example) in the main(), For android apps - in the Application class.
"You can clearly see there is no decoupling from the DI component, to the actual code" - Yes, you are 100% correct. That arises from the fact that you don't control directly the lifecycle of the activities, fragments and services in Android, i.e. the OS creates these objects for you and the OS is not aware that you are using DI. You need manually to inject your activities, fragments and services. At first this seem seems awkward but in real life the only problem is that sometimes you may forget to inject your activity in onCreate() and get NPE at runtime.
#SuppressWarnings("unsued")
#Override
#SuppressLint({ "InflateParams", "SimpleDateFormat" })
I don't get why we need to declare annotations.
We want to facilitate the writing and the maintenance of Android applications.
We believe that simple code with clear intents is the best way to achieve those goals.
Robert C. Martin wrote:
The ratio of time spent reading [code] versus writing is well over 10 to 1 [therefore] making it easy to read makes it easier to write.
While we all enjoy developing Android applications, we often wonder: Why do we always need to write the same code over and over? Why are our apps harder and harder to maintain? Context and Activity god objects, complexity of juggling with threads, hard to discover API, loads of anonymous listener classes, tons of unneeded casts... can't we improve that?
How?
Using Java annotations, developers can show their intent and let AndroidAnnotations generate the plumbing code at compile time.
Features
Dependency injection: inject views, extras, system services, resources, ...
Simplified threading model: annotate your methods so that they execute on the UI thread or on a background thread.
Event binding: annotate methods to handle events on views, no more ugly anonymous listener classes!
REST client: create a client interface, AndroidAnnotations generates the implementation.
No magic: As AndroidAnnotations generate subclasses at compile time, you can check the code to see how it works.
AndroidAnnotations provide those good things and even more for less than 50kb, without any runtime perf impact!
Is your Android code easy to write, read, and maintain?
Look at that:
#EActivity(R.layout.translate) // Sets content view to R.layout.translate
public class TranslateActivity extends Activity {
#ViewById // Injects R.id.textInput
EditText textInput;
#ViewById(R.id.myTextView) // Injects R.id.myTextView
TextView result;
#AnimationRes // Injects android.R.anim.fade_in
Animation fadeIn;
#Click // When R.id.doTranslate button is clicked
void doTranslate() {
translateInBackground(textInput.getText().toString());
}
#Background // Executed in a background thread
void translateInBackground(String textToTranslate) {
String translatedText = callGoogleTranslate(textToTranslate);
showResult(translatedText);
}
#UiThread // Executed in the ui thread
void showResult(String translatedText) {
result.setText(translatedText);
result.startAnimation(fadeIn);
}
// [...]
}
Java annotations bind specific conditions to be satisfied with code. Consider a scenario where we think we are overriding a method from anther class and we implemented code that (we think) is overriding the method. But if we somehow missed to exactly override one (e.g. we misspelled name. In superclass it was "mMethodOverridden" and we typed "mMethodoverridden"). The method will still compile and execute but it will not be doing what it should do.
So #Override is our way of telling Java to let us know if we are doing right thing. If we annotate a method with #override and it is not overriding anything, compiler will give us an error.
Other annotations work in a very similar way.
For more information, read docs Lesson: annotations
Annotations are basically syntactic metadata that can be added to Java source code.Classes, methods, variables, parameters and packages may be annotated .
Metadata is data about data
Why Were Annotations Introduced?
Prior to annotation (and even after) XML were extensively used for metadata and somehow a particular set of Application Developers and Architects thought XML maintenance was getting troublesome. They wanted something which could be coupled closely with code instead of XML which is very loosely coupled (in some cases almost separate) from code. If you google “XML vs. annotations”, you will find a lot of interesting debates. Interesting point is XML configurations were introduced to separate configuration from code. Last two statements might create a doubt in your mind that these two are creating a cycle, but both have their pros and cons.
For eg:
#Override
It instructs the compiler to check parent classes for matching methods.
I have been having quite a bit of trouble implementing unit testing on the Android. As a simple test, I've been trying to match a string retrieved from string resources:
String myString = myActivity.getResources().getString(R.string.testString));
However, when unit testing this invariably results in a null pointer exception. This includes robolectric as well as the Junit implementation delivered with the Android sdk.
One possible solution is to approach the retrieval of resources in a manner similar to a data access object. That is, create an interface through which string resources would be accessed. This would allow me to mock access the string resource. Similarly, I could separate the non-android dependent behavior of, say, an Activity, into a separate pojo class. This would allow me to run unit tests using standard Java testing tools. In fact, I could potentially delegate any Android infrastructure related activity to an interface.
This seems like a lot of jumping through hoops to get to unit testing. Is it worth it? Is there a more viable approach?
It turned out, the problem was that the activity has to be gotten in the actual test method. So, for example, my method now looks like this:
public void testGetActivityResourceString() {
Activity myActivity = this.getActivity();
String myString = myActivity.getResources().getString(R.string.hello);
Assert.assertNotNull(myString);
}
Whereas before I was creating activity in setup. This giveaway was in the docs:
"For each test method invocation, the Activity will not actually be created until the first time this method is called."
This was a real hassle to figure out. The example for HelloWorldTest doesn't work for the same reason.
Here's the full entry:
Public T getActivity ()
Since: API Level 3
Get the Activity under test, starting it if necessary.
For each test method invocation, the Activity will not actually be created until the first time this method is called.
If you wish to provide custom setup values to your Activity, you may call setActivityIntent(Intent) and/or setActivityInitialTouchMode(boolean) before your first call to getActivity(). Calling them after your Activity has started will have no effect.
NOTE: Activities under test may not be started from within the UI thread. If your test method is annotated with UiThreadTest, then your Activity will be started automatically just before your test method is run. You still call this method in order to get the Activity under test.
This works correctly:
public void testGetResourceString() {
assertNotNull(mActivity.getResources()
.getString(com.example.pkg.R.string.testString));
}
Because you haven't provided any of your code but only the getReousrces() line, I will guess what you are doing wrong:
you are not using the correct base class for your test, use ActivityInstrumentationTestCase2 because you need the system infrastructure
you are using the resources of your test project instead of your project under test, that's why in my example the id is com.example.pkg.R.string.testString.
I'm writing some tests to test my sqllite database code. Can someone here explain if there would be a difference writing those tests using the context I get from AndroidTestCase.getContext() or using an IsolatedContext.
For those that don't want to follow the link to the Google Group, here is the answer given there:
AndroidTestCase.getContext() returns a normal Context object. It's the
Context of the test case, not the component under test.
IsolatedContext returns a "mock" Context. I put "mock" in quotes
because its not a mock in the normal sense of that term (for testing).
Instead, it's a template Context that you have to set up yourself. It
"isolates" you from the running Android system, so that your Context
or your test doesn't accidentally get outside of the test fixture. For
example, an IsolatedContext won't accidentally hit a production
database (unless you set it up to do that!) Note, however, that some
of the methods in an IsolatedContext may throw exceptions.
IsolatedContext is documented in the Developer Guide under Framework
Topics > Testing, both in Testing Fundamentals and in Content Provider
Testing.
Here is the Android docs on IsolatedContext.
And here is the relevant section of the Testing Fundamentals document.
The answer:
http://groups.google.com/group/android-developers/browse_thread/thread/3a7bbc78258a194a?tvc=2
I had the simple problem: I need to test my DAO class without touching the real database. So I found the IsolatedContext from docs. But finally I found the other context in the same docs: RenamingDelegatingContext might be more easier to use. Here is my test case:
public class AddictionDAOTest extends AndroidTestCase {
#Override
public void setUp() throws Exception {
super.setUp();
setContext(new RenamingDelegatingContext(getContext(), "test_"));
}
public void testReadAllAddictions() throws Exception {
ImQuitDAO imQuitDAO = new ImQuitDAO(getContext());
...
}
}