Android: Verifying behavior using Unit Tests - java

So let's say I have a simple activity as follows. Assume all of the the lifecycle events etc. are correctly created there's no exception in creating an activity.
public class ButtonClickActivity extends Activity implements OnClickListener {
... onCreate etc. ...
#Override
public void onClick(View v) {
logInfo();
}
protected void logInfo() {
Log log = new Logger();
log.log('foo');
...
}
}
How exactly would you test that the onClickMethod calls on callMyOtherMethod? How also would you test that logInfo makes a new Logger and .log('foo')? Let's assume you have all frameworks at your disposal.
I've tried to use Robolectric (which is fine for high level testing, but really doesn't seem to let you get down into detail like to test if a method calls another method).
It seems that you have to use that in conjunction with a mocking framework / injection in order to verify at least injected object behavior. It doesn't to be able to test 'new Construction' so you're forced to use a factory always for every single object, even for objects you use from other frameworks etc.
I've given a shot with JMockIt (which allows you to verify every single new construction etc.) but it seems there is a problem there also with ByteCode manipulation and it basically will fail if it tries to rewrite bytecode for Android Activities and Views especially, along with other problems.
So my question for folks is what strategy have they been going with other than 'it's a implementation detail' or 'doesn't need to be tested'? I'm sure of course you don't want to test every little detail method call but letting important method calls go unverified doesn't seem like a good solution either.

Related

How to test a void method before implementing it?

I'm developing a new project. This is what has been done until now:
A technical design.
The model classes (data classes).
All the interfaces in the project (but no implementations yet).
Next thing I wanna do is implementing the methods from the skeleton (the high level methods) down to the nested objects. Nevertheless, I want to create a unit test for each method before I write the implementation. There won't be any problem to implement the high level methods first, because I'm going to work with interfaces and bind the concrete implementation only in an external Java configuration file using DI.
The first method I'm gonna implement is called lookForChanges() and it both accepts and returns void. This method is called by Spring's scheduler (#Scheduled), and it manages the whole process: it retrieves data from the DB, retrieves data from a web service, compares them, and if there were any changes then it updates the database and sends a JMS message to a client. Of course, it doesn't do all those things by itself but it calls the relevant classes and methods.
So the first problem I'd had is how to create a unit test to a void method. In all tutorials always the tested methods accept parameters and return a result. I've found an answer for that in this question. He says that even if there's no result to check, at least one can make sure that the methods inside the tested method were called and with the correct order of parameters.
I sort of liked this answer, but the problem is that I'm working TDD so in contast to the guy who asked this question, I'm writing the test before implementing the tested method, so I don't know yet which methods and in what order it will use. I can guess, but I will only be sure about that once the method will have been already implemented.
So, how can I test a void skeleton method before I implement it?
So the first problem I'd had is how to create a unit test to a void method.
A void method implies collaborators. You verify those.
Example. Suppose we needed a task that would copy System.in to System.out. How would we write an automated test for that?
void copy() {
// Does something clever with System.in and System.out
}
But if you squint a little bit, you'll see you really have code that looks like
void copy() {
InputStream in = System.in;
PrintStream out = System.out;
// Does something clever with `in` and `out`
}
If we perform and extract method refactoring on this, then we might end up with code that looks like
void copy() {
InputStream in = System.in;
PrintStream out = System.out;
copy(in, out);
}
void copy(InputStream in, PrintStream out) {
// Does something clever with `in` and `out`
}
The latter of these is an API that we can test - we configure the collaborators, pass them to the system under test, and verify the changes afterwards.
We don't, at this point, have a test for void copy(), but that's OK, as the code there is "so simple that there are obviously no deficiencies".
Notice that, from the point of view of a test, there's not a lot of difference between the following designs
{
Task task = new Task();
task.copy(in, out);
}
{
Task task = new Task(in, out);
task.copy();
}
{
Task task = Task.createTask();
task.copy(in, out)
}
{
Task task = Task.createTask(in, out);
task.copy();
}
A way of thinking about this is: we don't write the API first, we write the test first.
// Arrange the test context to be in the correct initial state
// ???
// Verify that the test context arrived in final state consistent with the specification.
Which is to say, before you start thinking about the API, you first need to work out how you are going to evaluate the result.
Same idea, different spelling: if the effects of the function call are undetectable, then you might as well just ship a no-op. If a no-op doesn't meet your requirements, then there must be an observable effect somewhere -- you just need to work out whether that effect is observed directly (inspecting a return value), or by proxy (inspecting the effect on some other element in the solution, or a test double playing the role of that element).
OK so now I can pass params to the method for testing it, but what can I test?
You test what it is supposed to do.
Try this thought experiment - suppose you and I were pairing, and you proposed this interface
interface Task {
void lookForChanges();
}
and then, after some careful thought, I implemented this:
class NoOpTask implements Task {
#Override
void lookForChanges() {}
}
How would you demonstrate that my implementation doesn't satisfy the requirements?
What you wrote in the question was "it updates the database and sends a JMS message to a client", so there are are two assertions to consider - did the database get updated, and was a JMS message sent?
The whole thing looks something like this
Given:
A database with data `A`
A webservice with data `B`
A JMS client with no messages
When:
The task is connected to this database, webservice, and JMS client
and the task is run
Then:
The database is updated with data `B`
The JMS client has a message.
It looks like what you suggest is an end-to-end test.
It does look like one. But if you use test doubles for these collaborators, rather than live systems, then your test is running in an isolated and deterministic shell.
It's probably a sociable test - the test doesn't know or care about the implementation details of the system under test in the when clause. I make no claims that the SUT is one-and-exactly-one "unit".
I have to see the implementation of foo first. Am I wrong?
Yes - you need to understand the specification of foo, not the implementation.

Unit testing a method which is inside an Android Activity

I don't know if it has been answered or not, I found some similar questions but the answers are not making any sense to me. So, I am asking it again.
How can we test a method which is inside an activity.
public class MyActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
//inflate layout
}
public int someMethod() {
//perform some logic and return an integer
}
}
I want to unit test the method someMethod but how can I do this as I cannot create an instance of the activity and directly call that method. The method under test does not use any android component so I dont want to use Roboelectric or any other such libraries or tools. It is a plain java method.
One way I know is to move the method to another class and have that class unit tested and I am perfectly fine with it, but I wanted to know if that is the right way, (create a separate class just for this purpose), or is there any other way to do it?
Thank you for any feedback.
To go a bit into theory, you do not want to test a single method in another class.
Following S.O.L.I.D. and D.R.Y. principles, your classes shall have a single responsibility.
So if you think that you want to test only one single method, this method clearly has another responsibility than the rest of the class. Which leads us to: It should not be in that particular class.
Unit Tests are only as good (and as valuable) as the plan behind the testing.
To answer your question: Yes you can call a new myActivitiy() and the unit test might run it (at least I think so). But if the method uses runtime values / context or any other thing from that activity, you can't without running Espresso or similar frameworks.
I recommend to create a proper object model that is testable.
Unit tests can only test code that is written testable
cheers, Gris

Mockito verify that ONLY a expected method was called

I'm working in a Project with a Service class and some sort of a Client that acts as a facade (don't know if it's the right term in the Design Patterns's world, but I'll try to make myself clear). Service's methods can be very expensive as they may be communicating with one or more databases, long checkings and so on, so every Client method should call one and only one Service method.
Service class structure is something like
public class Service {
public void serviceA(){...}
public SomeObject serviceB(){...}
// can grow in the future
}
And Client should be something like
public class Client {
private Service myService; // Injected somehow
public void callServiceA() {
// some preparation
myService.serviceA();
// something else
}
public boolean callServiceB(){...}
}
And in the test class for Client I want to have something like
public class ClientTest{
private Client client; // Injected or instantiated in #Before method
private Service serviceMock = mock(Service.class);
#Test
public void callServiceA_onlyCallsServiceA() {
client.callServiceA();
????
}
}
In the ???? section I want something like verifyOnly(serviceMock).serviceA() saying "verify that serviceMock.serviceA() was called only once and no other method from the Service class was called". Is there something like that in Mockito or in some other mocking library? I don't want to use verify(serviceMock, never()).serviceXXX() for every method because, as I said, Service class may grow in the future and I will have to be adding verification to every test (not a happy task for me) so I need something more general.
Thanks in advance for your answers.
EDIT #1
The difference between this post and the possible duplicate is that the answer adds boiler plate code which is not desired in my case because it's a very big project and I must add as few code as posible.
Also, verifyNoMoreInteractions can be a good option even when it's discouraged for every test, no extra boiler plate code needed.
To sumarize, the possible duplicate didn't solved my problem.
There's another issue: I'm writing test for code made by another team, not following a TDD proccess myself, so my test should be extra defensive, as stated in this article quoted in the mockito documentation for verifyNoMoreInteractions. The methods I'm testing are often very longs so I need to check that the method under test calls ONLY the necesary services and no other (because they're expensive, as I said). Maybe verifyNoMoreInteractions is good enough for now but I'd like to see something not being discouraged for every test by the very same API creator team!
Hope this helps to clarify my point and the problem. Best regards.
verify(serviceMock, times(1)).serviceA();
verifyNoMoreInteractions(serviceMock);
From Mockito's javadoc on verifyNoMoreInteractions:
You can use this method after you verified your mocks - to make sure that nothing else was invoked on your mocks.
Also:
A word of warning: Some users who did a lot of classic, expect-run-verify mocking tend to use verifyNoMoreInteractions() very often, even in every test method. verifyNoMoreInteractions() is not recommended to use in every test method. verifyNoMoreInteractions() is a handy assertion from the interaction testing toolkit. Use it only when it's relevant. Abusing it leads to overspecified, less maintainable tests.
The only way you can reliably verify that your service is only ever called once and only once from the method you specify and not from any other method, is to test every single method and assert that your serviceA method is never invoked. But you're testing every other method anyway, so this shouldn't be that much of a lift...
// In other test cases...
verify(serviceMock, never()).serviceA();
While this is undesirable from a code writing standpoint, it opens the door to separating out your service into smaller, more responsible chunks so that you guarantee that only one specific service is called. From there, your test cases and guarantees around your code become smaller and more ironclad.
I think what you are looking for is the Mockito.verify and Mockito.times
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
verify(mockObject, atLeast(2)).someMethod("was called at least twice");
verify(mockObject, times(3)).someMethod("was called exactly three times");
Here another thread with the same question:
Mockito: How to verify a method was called only once with exact parameters ignoring calls to other methods?

Is there a better way to test the following methods without mocks returning mocks?

Assume the following setup:
interface Entity {}
interface Context {
Result add(Entity entity);
}
interface Result {
Context newContext();
SpecificResult specificResult();
}
class Runner {
SpecificResult actOn(Entity entity, Context context) {
return context.add(entity).specificResult();
}
}
I want to see that the actOn method simply adds the entity to the context and returns the specificResult. The way I'm testing this right now is the following (using Mockito)
#Test
public void testActOn() {
Entity entity = mock(Entity.class);
Context context = mock(Context.class);
Result result = mock(Result.class);
SpecificResult specificResult = mock(SpecificResult.class);
when(context.add(entity)).thenReturn(result);
when(result.specificResult()).thenReturn(specificResult);
Assert.assertTrue(new Runner().actOn(entity,context) == specificResult);
}
However this seems horribly white box, with mocks returning mocks. What am I doing wrong, and does anybody have a good "best practices" text they can point me to?
Since people requested more context, the original problem is an abstraction of a DFS, in which the Context collects the graph elements and calculates results, which are collated and returned. The actOn is actually the action at the leaves.
It depends of what and how much you want your code to be tested. As you mentionned the tdd tag, I suppose you wrote your test contracts before any actual production code.
So in your contract what do you want to test on the actOn method:
That it returns a SpecificResult given both a Context and an Entity
That add(), specificResult() interactions happen on respectively the Context and the Entity
That the SpecificResult is the same instance returned by the Result
etc.
Depending on what you want to be tested you will write the corresponding tests. You might want to consider relaxing your testing approach if this section of code is not critical. And the opposite if this section can trigger the end of the world as we know it.
Generally speaking whitebox tests are brittle, usually verbose and not expressive, and difficult to refactor. But they are well suited for critical sections that are not supposed to change a lot and by neophytes.
In your case having a mock that returns a mock does look like a whitebox test. But then again if you want to ensure this behavior in the production code this is ok.
Mockito can help you with deep stubs.
Context context = mock(Context.class, RETURNS_DEEP_STUBS);
given(context.add(any(Entity.class)).specificResult()).willReturn(someSpecificResult);
But don't get used to it as it is usually considered bad practice and a test smell.
Other remarks :
Your test method name is not precise enough testActOn does tell the reader what behavior your are testing. Usually tdd practitioners replace the name of the method by a contract sentence like returns_a_SpecificResult_given_both_a_Context_and_an_Entity which is clearly more readable and give the practitioner the scope of what is being tested.
You are creating mock instances in the test with Mockito.mock() syntax, if you have several tests like that I would recommend you to use a MockitoJUnitRunner with the #Mock annotations, this will unclutter a bit your code, and allow the reader to better see what's going on in this particular test.
Use the BDD (Behavior Driven Dev) or the AAA (Arrange Act Assert) approach.
For example:
#Test public void invoke_add_then_specificResult_on_call_actOn() {
// given
... prepare the stubs, the object values here
// when
... call your production code
// then
... assertions and verifications there
}
All in all, as Eric Evans told me Context is king, you shall take decisions with this context in mind. But you really should stick to best practice as much as possible.
There's many reading on test here and there, Martin Fowler has very good articles on this matter, James Carr compiled a list of test anti-patterns, there's also many reading on using well the mocks (for example the don't mock types you don't own mojo), Nat Pryce is the co-author of Growing Object Oriented Software Guided by Tests which is in my opinion a must read, plus you have google ;)
Consider using fakes instead of mocks. It's not really clear what the classes in question are meant to to, but if you can build a simple in-memory (not thread-safe, not persistent etc) implementation of both interfaces, you can use that for flexible testing without the brittleness that sometimes comes from mocking.
I like to use names beginning mock for all my mock objects. Also, I would replace
when(result.specificResult()).thenReturn(specificResult);
Assert.assertTrue(new Runner().actOn(entity,context) == specificResult);
with
Runner toTest = new Runner();
toTest.actOn( mockEntity, mockContext );
verify( mockResult ).specificResult();
because all you're trying to assert is that specificResult() gets run on the right mock object. Whereas your original assert doesn't make it quite so clear what is being asserted. So you don't actually need a mock for SpecificResult. That cuts you down to just one when call, which seems to me to be about right for this kind of test.
But yes, this does seem frightfully white box. Is Runner a public class, or some hidden implementation detail of a higher level process? If it's the latter, then you probably want to write tests around the behaviour at the higher level; rather than probing implementation details.
Not knowing much about the context of the code, I would suggest that Context and Result are likely simple data objects with very little behavior. You could use a Fake as suggested in another answer or, if you have access to the implementations of those interfaces and construction is simple, I'd just use the real objects in lieu of Fakes or Mocks.
Although the context would provide more information, I don't see any problems with your testing methodology myself. The whole point of mock objects is to verify calling behavior without having to instantiate the implementations. Creating stub objects or using actual implementing classes just seems unnecessary to me.
However this seems horribly white box, with mocks returning mocks.
This may be more about the class design than the testing. If that is the way the Runner class works with the external interfaces then I don't see any problem with having the test simulate that behavior.
First off, since nobody's mentioned it, Mockito supports chaining so you can just do:
when(context.add(entity).specificResult()).thenReturn(specificResult);
(and see Brice's comment for how to do enable this; sorry I missed it out!)
Secondly, it comes with a warning saying "Don't do this except for legacy code." You're right about the mock-returning-mock being a bit strange. It's OK to do white-box mocking generally because you're really saying, "My class ought to collaborate with a helper like <this>", but in this case it's collaborating across two different classes, coupling them together.
It's not clear why the Runner needs to get the SpecificResult, as opposed to whatever other result comes out of context.add(entity), so I'm going to make a guess: the Result contains a result with some messages or other information and you just want to know whether it's a success or failure.
That's like me saying, "Don't tell me all about my shopping order, just tell me that I made it successfully!" The Runner shouldn't know that you only want that specific result; it should just return everything that came out, the same way that Amazon shows you your total, postage and all the things you bought, even if you've shopped there lots and are perfectly aware of what you're getting.
If some classes regularly use your Runner just to get a specific result while others require more feedback then I'd make two methods to do it, maybe called something like add and addWithFeedback, the same way that Amazon let you do one-click shopping by a different route.
However, be pragmatic. If it's readable the way you've done it and everyone understands it, use Mockito to chain them and call it a day. You can change it later if you have need.

How to test an anonymous inner class that calls a private method

We have a bunch of classes that listen for events from the server and then respond to them. For example:
class EventManager {
private Set<Event> cache = new HashSet<Event>();
private EventListener eventListener = new EventListener() {
void onEvent(Event e) {
if (e instanceof MyEvent || e instanceof YourEvent) {
handleEvent(e);
}
}
}
public EventManager(ServerCommunication serverComm) {
serverComm.addListener(eventListener);
}
private handleEvent(Event e) {
// handle the event...
// ...
cache.add(cache);
// ...
}
}
Here's a made-up example of the kind of thing we are doing. Here are the problems I see:
I'd like to test handleEvent to make sure it's doing what it is supposed to but I can't because it's private.
I'd also like to check that something got added to the cache too but that also seems difficult since cache is a private member and I don't want to add a needless getter method.
I'd also like to test the code inside the anonymous class's onEvent method.
For now, what I did was move all logic from the anonymous class to the handleEvent method, and I made handleEvent package private (my unit test is in the same package). I'm not checking the contents of the cache although I want to.
Does anyone have any suggestion for a better design that is more testable?
I would probably extract a EventCache component. You can replace this for your test with an implementation that counts the cached events or records whatever is of interest.
I probably would not change the visibility of handleEvent. You could implement a ServerCommunication that just raises the event from the test case.
Well, there are two approaches here: black box and white box.
Black box testing suggests you should only test the publicly visible changes. Does this method have any observable effect? (Some things don't - caches being an obvious example where they improve performance but may otherwise be invisible.) If so, test that. If not, test that it isn't having a negative effect - this may well just be a case of beefing up other tests.
White box testing suggests that maybe you could add a package-level method for the sake of testing, e.g.
Cache getCacheForTesting()
By putting "for testing" in the name, you're making it obvious to everyone that they shouldn't call this from production code. You could use an annotation to indicate the same thing, and perhaps even have some build rules to make sure that nothing from production does call such a method.
This ends up being more brittle - more tied to the implementation - but it does make it easier to test the code thoroughly, IMO. Personally I err on the side of white box testing for unit tests, whereas integration tests should definitely be more black box. Others are rather more dogmatic about only testing the public API.
I assume your EventManager is a singleton, or you have access to the particular instance of the class you're testing.
1 - I suppose you can send events to your class. Your method is private, and nobody else can call it, then sending an event should be enough.
2 - You can access that through reflection, if you really need to. Your test would depend on a particular implementation.
3 - What would you like to test, actually? If you want to be sure that this method is called, you can replace the EventListener with another EventListener object through reflection (and eventually call the onEvent method of the first listener from your new listener). But your question seems to be more about code coverage than actual unit-testing.
Sometimes, when coming across private methods that I want to test... they are simply screaming to be public methods on another object.
If you believe that HandleEvent is worth testing in isolation (and not through onEvent processing), one approach would be to expose HandleEvent as a public method on new/different object.
Use this opportunity to break the code up into smaller more focussed (default access) classes. A test is just another client for the code.
Note that the anonymous inner class' onEvent method is actually accessible, so calling it should not be a problem.

Categories

Resources