I'm using GMock to add some unit testing to our existing Java projects. We have multiple places where the methods needing to be tested are static methods, which utilize additional static methods within the method we want to test.
I would like to be able to partially mock the class, pretty much all static methods on the class other than the initial entry point for testing.
For example:
class StaticClass {
static void method(String one) {
method2()
}
static void method(String one, String two) {
...
}
}
My hope is that I can mock the second static method but as soon as I do, method(String) goes MIA and executing the test fails with an expectation exception. Is there a way I can partially mock the class, maintaining the functionality of the first method but mock the static access of the second method?
I've also tried using metaClass programming to mock the method, but if I set method equal to a closure, the first method goes MIA again. Not sure how to do this with overloaded methods. Any ideas?
In Gmock, it mocks static methods and matches expectations according to their names. It means you cannot mock one overloaded method but not another.
It is the same with MOP of Groovy.
While this doesn't involve GMock specifically, you could extend StaticClass inside your test file and override the methods there
Related
I am trying to test my Service class below
#Service
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
public class TaskTemplateService {
#NonNull
TaskTemplateRepository taskTemplateRepository;
public void doStuff() {
List<MyObject> list;
doOtherStuff(list)
}
private void doOtherStuff(List <MyObject>) {
//do stuff
}
}
When I am testing the real TaskTemplate, how can I capture what is passed to doOtherStuff?
You cannot and why would you?
Good testing means to specify the behaviour of a unit's public interface. Private methods ought to be covered via testing this way indirectly. If this is not possible then either you have dead, unreachable code or a design problem and should refactor.
BTW, the technical reason that you cannot mock/stub private methods is that most mocking tools, also the built-in feature of Spock, use dynamic proxies (DP) in order to implement mocking. DP technically are subclasses, but private methods can never be extended or even seen by subclasses or being called by them or from other classes, hence the term "private". Consequently, a mock subclass cannot check interactions with private methods.
How exactly you ought to redesign your class in order to make it testable really depends on why you want to "capture" the method argument, as you say. Do you need to replace it by a mock? Do you need to modify or verify the content of the original object?
If the object has a central meaning and you need to replace or verify it, why not make it injectable instead of creating it as a local variable, hermetically sealing it off from the outside world and making it untestable?
Or maybe in your case you could make the private method protected or package-scoped in order to make it testable. Then at least a mock could be created for it and you could capture the argument or stub the result.
I am mostly speculating here because the answer really depends on what is behind //do stuff, i.e. the very information you are hiding in your sample code.
I have a db service save() method which allows method chaining:
#Service
public class Service {
...
public Service save(...) {
...
return this;
}
and this works just great as:
service.save(this).save(that).save(other);
When I come to mock it with Mockito though it breaks unless I use
Service serviceMock = mock(Service.class, RETURNS_DEEP_STUBS);
IIUC though, the use of RETURNS_DEEP_STUBS is considered bad. Is there a better way to mock a class with method call chaining?
Your pattern for save is very similar to a Builder pattern, which makes the question similar to "How to mock a builder with mockito" elsewhere on SO.
Per David Wallace's answer there, you can write an Answer that detects whether the mock is an instance of the return type of the method, and return the mock in only that case. This functionality was also built into the Mockito library as RETURNS_SELF in Mockito 2.0. As with any Answer, you can use this on any specific method call with thenAnswer or as the second parameter of mock to make it the default answer, but bear in mind the Mockito documentation warning that methods with generous return types (e.g. Object) will return the mock whether or not that was intended.
I am trying to mock a call to a protected method of one of my classes:
import com.couchbase.client.java.view.Stale; // an enum
import com.google.common.base.Optional;
public class MyClass {
public List<String> myList(Optional<Integer> arg1, Optional<Stale> arg2) {
...
}
}
The mock shall be accomplished in the following way:
// Providing types for any() does not change anything
Mockito.when(myClass.myList(Mockito.any(), Mockito.any()).thenReturn(new ArrayList());
Whenever the previous line is executed the actual myList() method is called with null values for arg1 and arg2. Why is the method called, at all? After all, I am trying to avoid any executing thereof...
As Brice mentioned, if your myList method is final, then Java skips virtual method dispatch and will call the original object (not your mock).
If you are spying on an actual class, it is expected behavior that when will call the actual object as part of the stub: after all, in the expression when(foo.bar()) Java doesn't know anything special about when and assumes that it cares about the return value) of foo.bar(), not the call itself. (I walk through the stubbing process in the "Implementation details" section of my answer here.)
This syntax is better for spies:
doReturn(new ArrayList()).when(myClass).myList(any(), any());
Because this different when method receives an object, Mockito can prepare the object to do nothing during the stubbing, which avoids any spurious calls to your myList method.
Although Jeff's answer did not show a workaround for my problem it pointed me into the right direction.
After changing the mocking behaviour to doReturn... I suddenly got an error message. This message told me that myClass is not a mock which makes sense since you can only mock (or stub?) methods of mocked or spied objects. So as Jeff's answer indicates and is explained in the documentation of mockito I created a partial mock of MyClass with
MyClass myClass = Mockito.spy(new MyClass());
With this partial mock Jeff's approach to method mocking suddenly worked (mine still does not and should therefore be avoided).
So: Thank you, Jeff!
Thanks in advance for the help -
I am new to mockito but have spent the last day looking at examples and the documentation but haven't been able to find a solution to my problem, so hopefully this is not too dumb of a question.
I want to verify that deleteLogs() calls deleteLog(Path) NUM_LOGS_TO_DELETE number of times, per path marked for delete. I don't care what the path is in the mock (since I don't want to go to the file system, cluster, etc. for the test) so I verify that deleteLog was called NUM_LOGS_TO_DELETE times with any non-null Path as a parameter. When I step through the execution however, deleteLog gets passed a null argument - this results in a NullPointerException (based on the behavior of the code I inherited).
Maybe I am doing something wrong, but verify and the use of isNotNull seems pretty straight forward...here is my code:
MonitoringController mockController = mock(MonitoringController.class);
// Call the function whose behavior I want to verify
mockController.deleteLogs();
// Verify that mockController called deleteLog the appropriate number of times
verify(mockController, Mockito.times(NUM_LOGS_TO_DELETE)).deleteLog(isNotNull(Path.class));
Thanks again
I've never used isNotNull for arguments so I can't really say what's going wrong with you code - I always use an ArgumentCaptor. Basically you tell it what type of arguments to look for, it captures them, and then after the call you can assert the values you were looking for. Give the below code a try:
ArgumentCaptor<Path> pathCaptor = ArgumentCaptor.forClass(Path.class);
verify(mockController, Mockito.times(NUM_LOGS_TO_DELETE)).deleteLog(pathCaptor.capture());
for (Path path : pathCaptor.getAllValues()) {
assertNotNull(path);
}
As it turns out, isNotNull is a method that returns null, and that's deliberate. Mockito matchers work via side effects, so it's more-or-less expected for all matchers to return dummy values like null or 0 and instead record their expectations on a stack within the Mockito framework.
The unexpected part of this is that your MonitoringController.deleteLog is actually calling your code, rather than calling Mockito's verification code. Typically this happens because deleteLog is final: Mockito works through subclasses (actually dynamic proxies), and because final prohibits subclassing, the compiler basically skips the virtual method lookup and inlines a call directly to the implementation instead of Mockito's mock. Double-check that methods you're trying to stub or verify are not final, because you're counting on them not behaving as final in your test.
It's almost never correct to call a method on a mock directly in your test; if this is a MonitoringControllerTest, you should be using a real MonitoringController and mocking its dependencies. I hope your mockController.deleteLogs() is just meant to stand in for your actual test code, where you exercise some other component that depends on and interacts with MonitoringController.
Most tests don't need mocking at all. Let's say you have this class:
class MonitoringController {
private List<Log> logs = new ArrayList<>();
public void deleteLogs() {
logs.clear();
}
public int getLogCount() {
return logs.size();
}
}
Then this would be a valid test that doesn't use Mockito:
#Test public void deleteLogsShouldReturnZeroLogCount() {
MonitoringController controllerUnderTest = new MonitoringController();
controllerUnderTest.logSomeStuff(); // presumably you've tested elsewhere
// that this works
controllerUnderTest.deleteLogs();
assertEquals(0, controllerUnderTest.getLogCount());
}
But your monitoring controller could also look like this:
class MonitoringController {
private final LogRepository logRepository;
public MonitoringController(LogRepository logRepository) {
// By passing in your dependency, you have made the creator of your class
// responsible. This is called "Inversion-of-Control" (IoC), and is a key
// tenet of dependency injection.
this.logRepository = logRepository;
}
public void deleteLogs() {
logRepository.delete(RecordMatcher.ALL);
}
public int getLogCount() {
return logRepository.count(RecordMatcher.ALL);
}
}
Suddenly it may not be so easy to test your code, because it doesn't keep state of its own. To use the same test as the above one, you would need a working LogRepository. You could write a FakeLogRepository that keeps things in memory, which is a great strategy, or you could use Mockito to make a mock for you:
#Test public void deleteLogsShouldCallRepositoryDelete() {
LogRepository mockLogRepository = Mockito.mock(LogRepository.class);
MonitoringController controllerUnderTest =
new MonitoringController(mockLogRepository);
controllerUnderTest.deleteLogs();
// Now you can check that your REAL MonitoringController calls
// the right method on your MOCK dependency.
Mockito.verify(mockLogRepository).delete(Mockito.eq(RecordMatcher.ALL));
}
This shows some of the benefits and limitations of Mockito:
You don't need the implementation to keep state any more. You don't even need getLogCount to exist.
You can also skip creating the logs, because you're testing the interaction, not the state.
You're more tightly-bound to the implementation of MonitoringController: You can't simply test that it's holding to its general contract.
Mockito can stub individual interactions, but getting them consistent is hard. If you want your LogRepository.count to return 2 until you call delete, then return 0, that would be difficult to express in Mockito. This is why it may make sense to write fake implementations to represent stateful objects and leave Mockito mocks for stateless service interfaces.
I am using groovy to create some mock classes for a test case. I am basically creating dummy objects where all the methods return null so that i can run my testcase.
I am using the following syntax:
MessageFactory.instance = ["getMessage": {a,b,c,d -> "dummy"}] as MessageFactory
So here i am trying to overwrite the singleton instance with my on fake factory object. The problem is that MessageFactory's constructor happens to be a private method. This gives me an illigal access exception when i run the code above. Is there a away i can create a proxy in groovy and overcome the private constructor issue?
If you have access to the MessageFactory, and are willing to modify it, then you use the standard dependency-injection solution, as detailed here: mock singleton
..Though it's not particularly Groovy.
Otherwise, the best workaround I've found is to override the method(s) on the singleton instance itself, like so:
#Singleton
class Test{
def method(){"Unmocked method called"}
}
def test = Test.instance
test.metaClass.method = {-> null}
test.method() // Now returns null
Naturally, as a singleton, this instance doesn't change (at least in theory)... So, overriding methods in this manner is effectively global.
Edit: Or you can use GMock, which supports constructor mocking (among other things).