Android Studio Tip #002: Re-enable Test Artifact Switching
It's no doubt that Android Studio gets better with every version. Who doesn't love Instant Run? There is one thing I am sad to see change without mention. Test Artifacts are merged together by default now.
It's no doubt that Android Studio gets better with every version. Who doesn't love Instant Run? There is one thing I am sad to see change without mention. Test Artifacts are merged together by default now.
If you aren't familiar with testing or test artifacts in Android, Google themselves have created a really nice starting point answering most of your questions. Also I love to note that I am a huge fan of the Arrange-Act-Assert pattern and TDD. I would definitely check them out if you are new to testing or programming in general.
I usually run my tests at the command line via the same build task that will be run on the server. This validate that what I am working on will in fact pass on the server. However, if I want to debug through my tests in IDE I usually like to isolate which test artifact I am running. The reason being is that tests run on the regular JVM are usually faster and it means I don’t have to have a device connected to run them.
So if you are like me chances are that you would like to not have your tests ran together out of the box. In order to get back the old Android Studio behavior navigate to the Experimental tab in Preferences.
Preferences>Build, Execution, Deployment>Build Tools>Gradle>Experimental
And simply toggle off the Enable all tests…
box and apply. Voila! You now can switch between your Unit Tests and Android Instrumentation Tests.
TL;DR:
Mockito Verify Inconsistency
When I initially set out to blog about Mockito I wanted to write a post where I explained the Verify API. Though there wasn't much in the realm of posts around this topic, I think that the javadocs have ample examples. Maybe the only topic that would be worth covering for a second post would be good places to use Verify. I recently have been working a lot with the Verify API and found some inconsistencies that I wanted to share so that if you are using Mockito you can avoid the pain I had. So here it is two weeks later and here is my post about some caveats while using the Verify API.
When I initially set out to blog about Mockito I wanted to write a post where I explained the Verify API. Though there wasn't much in the realm of posts around this topic, I think that the javadocs have ample examples. Maybe the only topic that would be worth covering for a second post would be good places to use Verify. I recently have been working a lot with the Verify API and found some inconsistencies that I wanted to share so that if you are using Mockito you can avoid the pain I had. So here it is two weeks later and here is my post about some caveats while using the Verify API.
The Setup
I can't exactly share the original problem classes I had, yet, so instead I have recreated my problem in a set of examples. First, let's assume we have an interface called CallbackB
(original name, I know) and it takes SomeModel
as a parameter that we will say is only made up of a String.
public interface CallbackB{
public void someMethod(SomeModel model);
}
public class SomeModel{
private String text;
public SomeModel(String text){
this.text = text;
}
}
This interface defines the signatures for any class implementing it with the method someMethod
. Now let's say we have the following class that uses CallbackB
and we will call it ClassA
(again, super original):
public class ClassA {
private CallbackB mCallbacks;
public ClassA(CallbackB callbacks){
mCallbacks = callbacks;
}
public void doSomething(String text){
if(text.contains("Artoo")) {
mCallbacks.someMethod(new SomeModel(text));
}
}
}
You can see that ClassA
expects CallbackB
to be passed to it from the constructor, but I wouldn't be too focused on that, the important part is the usage of the method doSomething
.
You will notice that doSomething
takes a string and if the string contains the text Artoo (my dogs name... sorry, only thing that came to mind as an example string) then we will call someMethod
on our callbacks which is CallbackB
.
Ok, so that’s the setup. We have a class which will act as callbacks for us, as well as a class doing some business logic which triggers the callback.
Testing
So now let's say we want to test that our callback is called at the correct time and for the correct reasons. In our case, because we are writing an interface that we expect someone else to utilize to listen for things happening in our code we don't care as much about testing what happens when the concrete versions of the interface are called, but the fact that they are called. To do this we can utilize Mockito and a tool through it called verify
. If you have never used it I would highly suggest it. I will link to the docs for it but I don't want to spend time talking too much about how to use it. I may save that for another post if people actually want that.
So to test our interface our test could look something like this:
@Test
public void doSomethingIsCalledOnlyOnceAny(){
CallbackB mockedCallbackB = mock(CallbackB.class);
ClassA classA = new ClassA(mockedCallbackB);
String testStringHappy = "Artoo rocks!";
String testStringSad = "Rocks!";
classA.doSomething(testStringHappy);
classA.doSomething(testStringSad);
verify(mockedCallbackB).someMethod(any(SomeModel.class));
}
Hopefully, this test is straightforward, basically we want to verify that someMethod
is called only once and we don't care what the parameter passed to it is. This test will pass because of the way we built ClassA
, however if we take out:
if(text.contains("Artoo")) {
}
From the mix the test will fail because Mockito expects that the number of calls for that specific method should only be one. Now comes the oddity. let's say we use a custom argument matcher and also let's assume SomeModel has a getter to get the string. Here is what our ArgumentMatcher
could look like:
class IsValidSomeModel extends ArgumentMatcher<SomeModel> {
private String mExpected;
public IsValidSomeModel(String expected){
mExpected = expected;
}
public boolean matches(Object object) {
String actual = ((SomeModel) object).getText();
return actual.contains(mExpected);
}
}
Now that we have created the ArgumentMatcher
the new test should look like this:
@Test
public void doSomethingIsCalledOnlyOnceSpecific(){
CallbackB mockedCallbackB = mock(CallbackB.class);
ClassA classA = new ClassA(mockedCallbackB);
String testStringHappy = "Artoo rocks!";
String testStringSad = "Rocks!";
classA.doSomething(testStringHappy);
classA.doSomething(testStringSad);
verify(mockedCallbackB).someMethod(argThat(new IsValidSomeModel("Artoo"));
}
False Positive
So now we re-run the test suite. The first test will fail with the following error:
org.mockito.exceptions.verification.TooManyActualInvocations:callbackB.someMethod(<any>);
Wanted 1 time:-> at com.omitneedlesscode.mockitoverifyexample.VerifyTests.doSomethingIsCalledOnlyOnceAny(VerifyTests.java:26)
But was 2 times. Undesired invocation:-> at com.omitneedlesscode.mockitoverifyexample.ClassA.doSomething(ClassA.java:14)
However, the new test, mysteriously passes. Queue Twilight Zone music. I am still unsure why it is passing. However, I have come up with a temporary solution to the problem.
First and foremost, I would suggest not using the ArgumentMatcher
while using verify
. Instead I would suggest using the ArgumentCaptor it allows you to do assertions directly on the parameters themselves and seems to not be ailed by the mysterious passing test issue.
So let's say we want to go down this route. Here is a test with the ArgumentCaptor that will now properly fail due to too many invocations:
@Test
public void doSomethingIsCalledOnlyOnceSpecificCaptor() {
ArgumentCaptor<SomeModel> argument = ArgumentCaptor.forClass(SomeModel.class);
CallbackB mockedCallbackB = mock(CallbackB.class);
ClassA classA = new ClassA(mockedCallbackB);
String testStringHappy = "Artoo rocks!";
String testStringSad = "Rocks!";
String expected = "Artoo";
classA.doSomething(testStringHappy);
classA.doSomething(testStringSad);
verify(mockedCallbackB).someMethod(argument.capture());
assertTrue(argument.getValue().getText().contains(expected));
}
So hopefully if you are using Mockito, or thinking about using it, this helps make things clear. The Verify API is a great asset in your testing toolbox, but be weary of some inconsistencies. Use ArgumentCaptors instead of ArgumentMatchers and don’t give up on tests because you can’t get them to run. The work you put in will save you regressions to your code, new bugs and will always make your code better.
What developers should care about at I/O this year
Every year for the past 7 years the tech industry, financial analysts and tech aficionados alike post numerous blogs with rumors about the years I/O. This year is no exception. To give a different perspective, and maybe an altogether different approach, I have decided to come up with a few major things that Android developers should care about this I/O.
Every year for the past 7 years the tech industry, financial analysts and tech aficionados alike post numerous blogs with rumors about the years I/O. This year is no exception. To give a different perspective, and maybe an altogether different approach, I have decided to come up with a few major things that Android developers should care about this I/O. It's not to take away from the others who have spent time on an "I/O Prediction" article in the slightest, as I still love seeing what the rumor mill has to say. Hopefully, if you are coming to I/O to get something more out of your experience than just the keynote this will help you guide your course selection.
Code Labs
If I remember correctly, last year’s I/O did not have these. In 2013, I attended my first I/O which actually had the code labs and I was amazed how helpful it was. It makes a huge difference having someone there to help walk you through new APIs, to ask questions directly to a human being who has spent a good deal of their time working to understand how to use these APIs. In short, the code labs add great value to your I/O experience because it gives you scheduled time to work directly with all the cool things you just heard about in a subsequent talk.
This could be helpful not only with announcements related to this I/O, but could provide an opportunity to gain knowledge about other parts of Android you may be struggling with. Last year the lack of Code Labs meant that when I got home from I/O is when I really got deep into trying out new APIs and at that point it was much harder to solicit feedback. For some it was months until they were able to work with any of the Lollipop offerings and even worse for Material whose general support in pre-lollipop was decent, but still left us spending time exploring and asking questions on StackOverflow.
Battery, Rendering, Memory and Network Performance Tooling
This is a no brainer for many Android developers, but I feel it needs to be mentioned because making performance changes can be hard once you have written the code and even more complicated if you are reacting to bad press due to lots of jank. Colt McAnlis is a Developer Advocate for Android and has a series of youtube videos called Perf Matters. If you haven't watched this series yet, you have the rest of the day to catch up on these and if not please check it out after I/O. These are really great resources and worth your time to take a look.
Whether you are trying to get your app off the battery hog list, trying to make your UI snappy, helping to be a better user of system resource or trying to shave off data usage these talks will be a great jumping off point to making your app more performant and hopefully result in happy users.
It's important to note that this is in fact 4 different sandbox talks and thankfully they do not overlap at all, so be sure to attend them all.
Testing
Last, but not least is testing. I am unsure if this topic has even been covered at Google I/O in years previous, but I feel that in the 2 years that I have been in attendance I have yet to see anything major on this front. Hopefully this will be a really great series as well. Google will focus on both Unit (White box) and System testing (Black box) which is monumental and well timed with the recent announcment of the Android Testing Support Library which helps unifiy all aspects of testing in Android. Testing like many things in computer science is not a silver bullet, but makes a considerable difference in reducing your tech debt and in turn giving you and your team more time to work on adding all the new features we get tomorrow. It's also important to note that Google has done a lot to make testing a first class citizen of Android Studio. There is no doubt that these talks will be heavy in talking about how to structure, write, integrate and run tests. Not to mention a few years ago Google created a framework for system testing called Espresso, and this will be the first I/O talk that they will give about it so expect to learn a lot!
I feel like after seeing this years I/O schedule we are going to have a lot of tough decisions ahead of us. Not to say that any of the other talks are not going to be informative or worth attending. These are all extremely important topics and while the new stuff may entice you away from these just remember, the new stuff is recorded and when you are deep in a heap trace or debugging visual jank in your UI, was missing these worth the extra hours you will spend now going to look this info up?