I have a function isChanged which emits Observable<Boolean>. I defined a function which uses the stream like so:
Observable<Boolean> myFunc() {
return isChanged().skip(1).distinctUntilChanged();
}
Now, I want to test whether the skip(1) works as desired. So I created a BehaviorSubject<Boolean> subject as simply:
BehaviorSubject<Boolean> subject = BehaviorSubject.create();
In my test function, I have (with the proper mocks and initializations):
when(isChanged()).thenReturn(subject);
subject.onNext(true);
subject.onNext(false);
myFunc().test().assertValueCount(1);
This assertion fails, and the error it provides is that the expected value count is 1, whereas the actual is 0.
The test passes when I remove the skip() condition, which makes me realize it's got something to do with the assertion checking only the latest value from the subject.
Not super clear on this, any help would be highly appreciated!
Edit:
The isChanged() is actually a placeholder for a custom switch's custom function. So, I actually have a mock for that switch (called switchMock) and my actual statement is when(switchMock.isChanged()).thenReturn(subject). Not sure if the specifics are needed here. Would be happy to provide additional information, of course!
BehaviorSubject holds one item, which you overwrote in your tests and then started observing the subject. At this point, the subject will emit its single value which gets dropped by skip and thus the test correctly fails with no items. You have to start observing earlier:
when(isChanged()).thenReturn(subject);
TestObserver<Boolean> to = myFunc().test();
subject.onNext(true);
subject.onNext(false);
to.assertValueCount(1);
Related
I have the following class
public class Multiplier {
private static Map<Integer, Float> map;
private static final float DEFAULT_MULTIPLIER = 4.4F;
static {
// This map is actually populated by reading from a file. This is an example on how the map looks like.
map = new HashMap<>();
map.put(1, "3.5F");
map.put(2, "5.8F");
map.put(3, "2.7F");
}
public static float getMultiplier(Integer id) {
return map.getOrDefault(id, DEFAULT_MULTIPLIER);
}
}
I want to test the getMultiplier method. What's the best way to go about it?
1st - There are 1000s of entries inside the map. Should I just call the getMultiplier method with a couple of different ids and make sure the value returned matches? The file is static. It will occasionally change in the future, but that would mean updating the test, which is fine.
2nd - I want to test the default value as well. Should I just do something like
Assert.assertEquals(4.4F, Multiplier.getMultiplier(<invalidId/null>));
I'm hardcoding the DEFAULT_MULTIPLIER value in the expected parameter of assertEquals. Does this even make sense?
I want to know what's the right way to unit test this method? Thanks!
You shouldn't be testing any of that - it's got way too much of a "Grading your own exam" vibe. The likely errors here involve you messing up either the constant, or the static file, which a test is not likely to catch. You'll be setting yourself up for a bunch of future updates (where you update the default and then later go: Oh, right, of course, I repeated myself in the test and I forgot to update the value there). You're not testing anything - you're giving your future self pointless homework.
Get creative - what could plausibly fail in the future? Not much - this is rather simple code. Test the likely failure avenues.
If I were you, I'd test the following situations:
I would check that the value for a key I'm sure is never going to be in the map (not now, and not likely ever in the future) returns non-0. This avoids having to hardcode the 4.4F, or having to mark as package-private the constant value, but still ensures 2 unlikely but plausible avenues of future failure: That the .getMultiplier method throws an exception due to a bug in the future, or that it returns 0 instead of an actual value. It would avoid having to update the test if you change this default later. Unless you change it to 0 or to 'if you ask for the multiplier for a number not listed, the method now throws', which are fundamental changes to functionality and therefore should indeed cause tests to fail.
I would not test any value from the static file, because either you're again just testing that you correctly copied and pasted a value from it into your test source file and giving yourself future homework to update the tests when you update the file - or you're marking your own exam if you dynamically adjust the k/v pair you test by also getting it from the file (whatever bug might exist in the code that reads in this static file, it'll be in the test code too). Instead, I would take the thing that is capable of reading in the static file and turning it into that static 'map of constants' and test that. In the test code I can then have a tiny example 'input static file' and I would then test if the Multiplier class responds correctly given this known input. This frees you from future updates (the test code always supplies test static data to the code, it doesn't look at the thing that may be updated in the future and is therefore essentially 'unstable'), and lets you test the thing that could plausibly break here - the part that turns the static file into a filled map.
Once tests ensure that the 'turn static file into static map' code works, and I have tested that the getMultiplier method doesn't fail in the 2 obvious ways (throws, or, returns 0), then you've tested everything relevant.
I want to test my Java service with Spock Groovy, and the service is a bit tricky, because a method call returns a value and also changes the content of the variable which was passed to the method.
Since I want to mock this method call, I need to tell Spock somehow that when the method was executed, return a specific value AND change the content of the passed variable.
Something like this:
given: "list with one element"
List<String> list = ["mock"]
when: "executing the service call"
service.execute(list)
then: "external method is called, which updates the passed variable and returns true as success"
1 * external.addOneMoreToList(list) >> true
and: "list is updated successfully"
list.size == 2
list.get(1) == "mock 2"
But I don't know where and how to update the list by adding the next element: "mock 2".
I know this example does not make sense, but I didn't want to write my real testcase, because it is huge, but I need similar ad-hoc-update
Use a closure instead of a simple value for the interaction, like this:
1 * external.addOneMoreToList(list) >> { list ->
list << 'mock 2'
return true
}
A few idiomatic notes:
It's not actually necessary to return true in this case, since (assuming your return type is boolean) Groovy will consider the non-empty list truthy. It's still a good idea to be clear.
As in JUnit, expected values come first, then actual values (2 == list.size()).
You can index into a List with []: 'mock 2' == list[1].
It's a good idea whenever practical to use random values, such as for your 'mock 2' value, since this helps prevent accidental passes. You can set variables in your given block and use them in interactions; I typically use commons-lang3 RandomStringUtils.
And try to slim down your test case to whatever extent practical! Spock's friendly interaction mocking makes it much less painful to use test doubles for interfaces that are perhaps too complicated, and extended interactions can be a reasonable use case for #Stepwise (I've used it for Selenium tests with multi-step scenarios).
I'm trying to verify the object by using
#Captor
ArgumentCaptor<User> userArgumentCaptor
...//define user with name and jailName - var = user1
...//Call the method under test.
verify(userDao).getName(userArgumentCaptor.capture());
verify(userDai).getJailName(userArgumentCaptor.capture());
assertThat(userArgumentCaptor.getAllValues()).isEqualTo(Arrays.asList(user1user1));
/**
* Notice here that I had to use same object to verify even when I captured it in two different situations.
*/
for the scenario,
User user = new User(); //Object under inspection.
user.setId(); //Changing state here.
userDao.getName(user); //Capture user here.
...
if(someBooleanCondition) {
user.setJailStatus(true); //Changing state here.
userDao.getJailName(user); //Capture user here.
}
While asserting the userArgumentCaptor.getValue(), it is checking the updated value. This actually makes sense since I'm capturing the object not object's state.
But, how do I verify the object's state when it was passed?
I think this is not possible. Even when checking out the very latest version of ArgumentCaptor (mockito 2.7.21 at this point); there is no indication at all to go in that direction.
The purpose respectively service offered by ArgumentCaptor is to collect those parameters used when a method is called.
What you are asking is basically: is there a way to do additional checking at the point when that call happens.
I guess, it could be made possible: the framework would have to allow you to register a callback, that is called whenever a specific method is invoked on a mock object. But that isn't possible today.
The only solution I see - instead of doing
#Mock
YourRealDaoClass theMockedDao
You would have to do
class MockedDaoClass extends YourRealDaoClass {
and then implement such things yourself. So that you can put:
YourRealDaoClass theMockedDao = new MockedDaoClass(...
into your tests. Together with a some other logic to enable the things you need.
In other words: the mocks generated by Mockito do not allow you to do enhanced testing at the point when methods are invoked on mocked objects. If you need that (for example to do a test like: param.getFoo().equals()) then you are back to creating your own stub/mock class.
What you have to do:
carefully check all the methods that the Dao class has
decide which one you need to overwrite, to make sure that they return the values you need to make the mock work with your production code
for the methods that receive those parameters you are interested in: either do checking right there; or collect the values for later checking
I have the following code:
when(mockedOperation.getResult(anyDouble(), anyDouble())).thenCallRealMethod();
when(mockedOperation.division(anyDouble(), not(eq(0d)))).thenCallRealMethod();
Where Operation is something like Command pattern - it encapsulates some concrete action, in this case, simplified - division operation. The result retrieval happens not directly, but by the means of contract method, say getResult(arg1, arg2). So, I call
mockedOperation.division(10d, 3d);
But (from debugging info in my concrete implementation of Operation) I can see that division() gets not 10 and 3 but (0, 0).
As far as I understand, that arguments are lost somewhere between the thenCallRealMethod() by getResult() and calling real division() afterwards.
What is the reason for that behavior and how should I implement partial mocks correctly in case I really need it?
UPD. Maybe I should try to say it another way, for example, simply how do you create mocks that callRealMethod in such a way that arguments are correctly delivered to the endpoint?
OK, the problem is solved now. Turns out I just encountered another undocumented feature/bug in Mockito (or just the feature I didn't find the docs for yet). The problem was that in my #Before I also mocked that very operation, and, as it appears, when one redefines mock, something black-magical happens and the result is as I've already described - arguments are somehow lost.
I am attempting to set up a when statement for a method used inside another method I am testing. Inside the method I am testing I am creating a list which I have no reference to, therefore I cannot mock it. I would like to validate the contents of this list when it is used in the above mentioned method inside. I have used the following as part of the when method, but ended up with an "InvalidUseOfMatchersException" in every case. What am I missing?
Matchers.eq(mockKeys) //mockKeys is a List<String> with expected contents
Matchers.anyListOf(String.class)
Mockito.when(myDaoImpl.getRecords([either of the above])).thenReturn(mockResult);
I must refuse to provide exact code.
List<String> mockKeys = createMockKeys(); // defined elsewhere
when(myDaoImpl.getRecords(Matchers.eq(mockKeys))).thenReturn(mockResult);
when(myDaoImpl.getRecords(mockKeys)).thenReturn(mockResult); // implicitly equal
when(myDaoImpl.getRecords(Matchers.anyListOf(String.class)))
.thenReturn(mockResult);
All of the above are fine. Nothing you've posted looks inherently wrong; it's more likely a problem we can't see, such as if getRecords is final, or in a use of Mockito or Matchers surrounding your code. Though it is understandable not to be able to post more code than you can, it may make it hard to provide a more-specific answer.
For the sake of debugging, place a call to Mockito.validateMockitoUsage() before and after your stub. This will help ensure that the problem is actually on the line you think it is, and not pollution from calls before or after.
Your problem is the two lines Matchers.eq(mockKeys); and Matchers.anyListOf(String.class). As the message says, you're using them invalidly.
Mockito uses its own data structure to store a matcher when you call such a method, but returns a different value from the actual call. That additional value must be passed to the method that you're stubbing (getRecords in this case), and when you stub, Mockito retrieves the actual matchers from the data structure.
Unless you completely understand how the data structure works, and know exactly what you're doing, you really need to put the calls to the two Matchers methods inside the call to getRecords. For example,
when(myDaoImpl.getRecords(eq(mockKeys), anyListOf(String.class))).thenReturn(mockResult);