Use Mockito to unit test a function which calls async function - unit-testing

I have a method which calls async function:
public class MyService {
...
public void uploadData() {
MyPool.getInstance().getThreadPool().execute(new Runnable() {
#Override
public void run() {
boolean suc = upload();
}
});
}
}
I want to unit test this function with Mockito, I tried:
MyPool mockMyPool = Mockito.mock(MyPool.class);
ThreadPool mockThreadPool = Mockito.mock(ThreadPool.class);
ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
when(mockMyPool.getThreadPool()).thenReturn(mockThreadPool);
MyService service = new MyService();
// run the method under test
service.uploadData();
// set the runnableCaptor to hold your callback
verify(mockThreadPool).execute(runnableCaptor.capture());
But I got error:
org.mockito.exceptions.verification.WantedButNotInvoked:
Wanted but not invoked:
threadPool.execute(
<Capturing argument>
);
Why I got this error, how to unit test uploadData() function with Mockito?

OK, I figured out a way by myself, since MyPool is an singleton. I added one public function setInstance(mockedInstance) to pass the mocked instance to MyPool. Then, it works. I know it is a bit "dirty", but if you have better solution, please let me know. Thanks!

Aside from the DI approach you found of keeping a MyPool or ThreadPool field, you can also refactor a little bit to allow for dependency injection in your method:
public class MyService {
...
public void uploadData() {
uploadData(MyPool.getInstance().getThreadPool());
}
/** Receives an Executor for execution. Package-private for testing. */
void uploadData(Executor executor) {
executor.execute(new Runnable() {
#Override public void run() {
boolean suc = upload();
}
});
}
}
This might be even cleaner, because it reduces your ThreadPool to the level of abstraction you need (Executor), which means you're only mocking a one-method interface rather than your ThreadPool (which I assume is related to ThreadPoolService; otherwise, you can just accept a ThreadPool, too). Officially your uploadData() would be untested, but you could easily and thoroughly test uploadData(Executor) or uploadData(ThreadPool), which are the moving parts most likely to break.
The package-private trick does rely on your code and tests to be in the same package, though they could be in different source folders; alternatively, you could just make the ThreadPool-receiving call a part of your public API, which would allow for more flexibility later.

Related

Fake internal calls of a SUT with FakeItEasy

I have a small C# class that handles printing.
I want to create (n)unit tests for this class, using
fakeItEasy. How can I fake the internal calls of this
class without faking the whole SUT ?
For example:
public class MyPrintHandler: IMyPrintHandler
{
public MyPrintHandler(ILogger<MyPrintHandler> logger)
{
}
// function I want to (unit test
public async Task<bool> PrintAsync(string ipaddress)
{
try
{
if (!string.IsNullOrWhiteSpace(ipaddress) )
{
return await StartPrint(ipaddress); // This cannot be called in a unit test, because it really start printing on a printer.
}
}
catch (Exception e)
{
}
return false;
}
private async Task<bool> StartPrint(string ipaddress)
{
// prints on the printer
}
[TestFixture]
public class MyPrintHandlerTests
{
[Test]
public void Succes_PrintAsync()
{
using (var fake = new AutoFake())
{
// Arrange - configure the fake
var sut = fake.Resolve<MyPrintHandler>();
// Act
await sut.PrintAsync("0.0.0.0"); // I want to prevent StartPrint() from being called..
}
}
}
How can I achieve this, or is this not possible at all?
Thanks in advance!
I would typically say that faking the SUT is an anti-pattern, to be avoided whenever possible, as it causes confusion. If you can refactor to introduce a collaborator that handles the StartPrinting method, I would strongly consider doing so. If this is not possible, you can try this, however
any method that you want to fake must be virtual or abstract, otherwise FakeItEasy cannot intercept it
any method that you want to fake must be public (or internal, if you can grant dynamic proxy access to production code's internals)
you would then fake the SUT, specifying that it should call the original (base) methods, and finally
explicitly override the behaviour for the method that you want to intercept

Wanted but not invoked: Mockito and Retrofit

I'm trying to unit test a call to my api using Mockito.
I took a look at all the issues already mentioned here on S.O together with the solutions, but so far, none of them have been conclusive.
MyService is an interface which holds several resources. Here's a sample:
public interface MyService {
#GET("/myresource")
Call<MyResponse> getDataFromServer();
}
Inside my Application class, I have a static class which returns an instance of MyService
public static MyService getApiService() {
return mApiService;
}
So, from there on inside one of my classes, I make the call to the web service:
Call<MyResponse> call = getApiService.getDataFromServer();
call.enqueue(myCallback)
The rest follows with the callback method being called....
Here's my test class:
#RunWith(AndroidJUnit4.class)
public class SampleTest {
#Mock
private MyService mService;
#Captor
private ArgumentCaptor<Callback<MyResponse>> callbackArgumentCaptor;
#Mock
private Call<MyResponse> mockCall;
// Rule to trigger the creation of #Mock annotated objects.
#Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
#Test
public void testDoAction() throws NullInsteadOfMockException {
when(mService.doSomeAction()).thenReturn(mockCall);
mService.doSomeAction();
verify(mockCall).enqueue(callbackArgumentCaptor.capture());
}
}
Here's the error I have once I run the test:
Wanted but not invoked:
mockCall.enqueue(
<Capturing argument>
);
Actually, there were zero interactions with this mock.
I have the same error even if use MockitoJunitRunner (in place of AndroidJunitRunner) and initialize my mock objects inside a setup method I define like this:
#Before
public void setUp() throws Exception{
MockitoAnnotations.initMocks(this);
}
Mockito version : 2.7.19
I want to be able to test the API response, so I mocked the API service, defined a captor for the retrofit Callback
It's a bit strange what you're trying to do here. You're testing a class, but you mock it. You should test the real class - MyService. I assume that your service looks a bit like:
public class MyService {
private final Call<MyResponse> call;
public MyService(Call<MyResponse> call) {
this.call = call;
}
public void doSomeAction() {
call.enqueue(...);
}
}
Ideally you should have something like:
#RunWith(AndroidJUnit4.class)
public class SampleTest {
private MyService mService;
#Captor
private ArgumentCaptor<Callback<MyResponse>> callbackArgumentCaptor;
#Mock
private Call<MyResponse> mockCall;
#Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
#Before
public void setUp() throws Exception{
MockitoAnnotations.initMocks(this);
mService = new MyService(mockCall);
}
#Test
public void testDoAction() throws NullInsteadOfMockException {
mService.doSomeAction();
verify(mockCall).enqueue(callbackArgumentCaptor.capture());
}
}
So the idea is to mock all the dependencies of the class you're unit testing and pass them to the class somehow. Here I'm injecting them in the constructor. I don't know if this is the case for you, but a setter or a field works too.
Then the test simply calls the real method in the service class and if this method is suppose to enqueue the call, then the verify should pass.
The reason it doesn't work in your case is because you're mocking the service so when you call mService.doSomeAction() this doesn't call your implementation, which I suppose should call enqueue. This is why the verify fails. In other words, it's true that enqueue is never called on the call object.

JUnit Scheduler that doesn't depend on Android

I´m trying to use MVP to enhance unit testing and run tests faster (because I'm testing logic not android code so I avoid using things like RobotElectric).
But I´m using RXAndroid and it needs Looper to get Schedulers.io() and AndroidSchedulers.mainThread() and when I try to run sometime like
class Phone {
public Observable<> sendSms(String number){
//...
}
}
Phone.getInstance().sendSms(phoneNumber)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(phone -> {
mView.dismissProgress();
mView.startCodeView(phone);
}, error -> {
mView.dismissProgress();
mView.showError(error);
});
I get:
Caused by: java.lang.RuntimeException: Method getMainLooper in android.os.Looper not mocked. See http://g.co/androidstudio/not-mocked for details.
at android.os.Looper.getMainLooper(Looper.java)
at rx.android.schedulers.AndroidSchedulers.<clinit>(AndroidSchedulers.java:27)
... 28 more
I tried:
android {
// ...
testOptions {
unitTests.returnDefaultValues = true
}
}
But it will not work because I want to run full JUnit tests and not Roboelectric or Espresso stuff.
How can I accomplish it? is there any Scheduler that will not crash because of this?
I am also using scheduler thread for this, but in my test SetUp and TearDown.
#Before
public void setUp() throws Exception {
RxAndroidPlugins.getInstance().registerSchedulersHook(new RxAndroidSchedulersHook() {
#Override
public Scheduler getMainThreadScheduler() {
return Schedulers.immediate();
}
});
}
#After
public void tearDown() {
RxAndroidPlugins.getInstance().reset();
}
Will this help?
I ended up adding using transformations and "flavour injection classes" for this, have a class that uses the main for prod/debug releases and use another class in the test flavour folder for testing Schedulers.immediate().
normal flavoured class:
public class Transformer {
public static <T> Observable.Transformer<T, T> applyIoSchedulers() {
return observable -> observable.subscribeOn(getIoScheduler())
.observeOn(getMainScheduler());
}
private static Scheduler getIoScheduler() {
return Schedulers.io();
}
private static Scheduler getMainScheduler() {
return AndroidSchedulers.mainThread();
}
}
Testing flavoured class:
public class Transformer {
public static <T> Observable.Transformer<T, T> applyIoSchedulers() {
return observable -> observable.subscribeOn(getIoScheduler())
.observeOn(getMainScheduler());
}
private static Scheduler getIoScheduler() {
return Schedulers.immediate() ;
}
private static Scheduler getMainScheduler() {
return Schedulers.immediate() ;
}
}
Then use it with transformations:
mSessionRepository.login(...)
.compose(Transformer.applyIoSchedulers())
.subscribe(session -> { })
In our practice, we try to avoid using AndroidSchedulers.mainThread() in Presenter because it's a detail of View implementation. You can do this too.
Though we use Robolectric, so anyway it'll work in our tests.
Yup, no android.jar in junit tests means no Loopers. If you use Dagger you can inject a mock scheduler into tests and a real scheduler into source code. You could also use something like Mockito to mock the Scheduler. Otherwise like #Artem Zinnatullin suggested, Robolectric solves this problem. Robolectric 3 is very easy to setup with Android Studio.

Mockery - creating a mock in the constructor

Is there a way to create a mock in the test class constructor/class setUp function such that the mock is available to all test methods?
I have tried creating in the constructor like:
public class testMocks extends PHPUnit_Framework_TestCase {
protected $mock;
public function __construct()
{
$this->mock = Mockery::mock('myMockedClass');
}
...
But this doesn't work. If the first test passes, then all tests that assert on the mock pass even if they should fail (i.e running a shouldReceive that should fail). Any ideas?
You have to use setUp function, like this:
public function setUp()
{
$this->mock = Mockery::mock('myMockedClass');
}
You shouldn't overwrite the constructor of PHPUnit_Framework_TestCase, see my answer on #15051271 and also #17504870
You also need to call Mockery::close() on tearDown method. The close method cleans up the mockery container for your next test and runs the expectations you have setup.
public function tearDown()
{
Mockery::close();
}

How to unit test an interceptor?

I want to write some unit tests for an interceptor that intercepts the Loggable base class (which implements ILoggable).
The Loggable base class has no methods to call and it is used only to be initialized by the logging facility.
To my understanding I should:
Mock an ILoggable and an ILogger
Initialize the logging facility
Register my interceptor on it
Invoke some method of the mocked ILoggable
The problem is that my ILoggable interface has no methods to call and thus nothing will be intercepted.
What is the right way to act here?
Should I mock ILoggable manually and add a stub method to call?
Also, should I be mocking the container as well?
I am using Moq and NUnit.
EDIT:
Here's my interceptor implementation for reference:
public class LoggingWithDebugInterceptor : IInterceptor
{
#region IInterceptor Members
public void Intercept(IInvocation invocation)
{
var invocationLogMessage = new InvocationLogMessage(invocation);
ILoggable loggable = invocation.InvocationTarget as ILoggable;
if (loggable == null)
throw new InterceptionFailureException(invocation, string.Format("Class {0} does not implement ILoggable.", invocationLogMessage.InvocationSource));
loggable.Logger.DebugFormat("Method {0} called with arguments {1}", invocationLogMessage.InvokedMethod, invocationLogMessage.Arguments);
Stopwatch stopwatch = new Stopwatch();
try
{
stopwatch.Start();
invocation.Proceed();
stopwatch.Stop();
}
catch (Exception e)
{
loggable.Logger.ErrorFormat(e, "An exception occured in {0} while calling method {1} with arguments {2}", invocationLogMessage.InvocationSource, invocationLogMessage.InvokedMethod, invocationLogMessage.Arguments);
throw;
}
finally
{
loggable.Logger.DebugFormat("Method {0} returned with value {1} and took exactly {2} to run.", invocationLogMessage.InvokedMethod, invocation.ReturnValue, stopwatch.Elapsed);
}
}
#endregion IInterceptor Members
}
If it's just the interceptor that uses the Logger Property on your class than why have in there at all? You might just as well have it on the interceptor. (like Ayende explained in his post here).
Other than that - interceptor is just a class which interacts with an interface - everything highly testable.
I agree with Krzysztof, if you're looking to add Logging through AOP, the responsibility and implementation details about logging should be transparent to the caller. Thus it's something that the Interceptor can own. I'll try to outline how I would test this.
If I follow the question correctly, your ILoggable is really just a naming container to annotate the class so that the interceptor can determine if it should perform logging. It exposes a property that contains the Logger. (The downside to this is that the class still needs to configure the Logger.)
public interface ILoggable
{
ILogger { get; set; }
}
Testing the interceptor should be a straight-forward process. The only challenge I see that you've presented is how to manually construct the IInvocation input parameter so that it resembles runtime data. Rather than trying to reproduce this through mocks, etc, I would suggest you test it using classic State-based verification: create a proxy that uses your interceptor and verify that your log reflects what you expect.
This might seem like a bit more work, but it provides a really good example of how the interceptor works independently from other parts of your code-base. Other developers on your team benefit from this as they can reference this example as a learning tool.
public class TypeThatSupportsLogging : ILoggable
{
public ILogger { get; set; }
public virtual void MethodToIntercept()
{
}
public void MethodWithoutLogging()
{
}
}
public class TestLogger : ILogger
{
private StringBuilder _output;
public TestLogger()
{
_output = new StringBuilder();
}
public void DebugFormat(string message, params object[] args)
{
_output.AppendFormat(message, args);
}
public string Output
{
get { return _output.ToString(); }
}
}
[TestFixture]
public class LoggingWithDebugInterceptorTests
{
protected TypeThatSupportsLogging Input;
protected LoggingWithDebugInterceptor Subject;
protected ILogger Log;
[Setup]
public void Setup()
{
// create your interceptor
Subject = new LoggingWithDebugInterceptor();
// create your proxy
var generator = new Castle.DynamicProxy.ProxyGenerator();
Input = generator.CreateClassProxy<TypeThatSupportLogging>( Subject );
// setup the logger
Log = new TestLogger();
Input.Logger = Log;
}
[Test]
public void DemonstrateThatTheInterceptorLogsInformationAboutVirtualMethods()
{
// act
Input.MethodToIntercept();
// assert
StringAssert.Contains("MethodToIntercept", Log.Output);
}
[Test]
public void DemonstrateNonVirtualMethodsAreNotLogged()
{
// act
Input.MethodWithoutLogging();
// assert
Assert.AreEqual(String.Empty, Log.Output);
}
}
No methods? What are you testing?
Personally, this sounds like it goes too far. I realize that TDD and code coverage is dogma, but if you mock an interface with no methods and prove that the mocking framework does what you instructed it to do, what have you really proven?
There's another misdirection going on here: logging is the "hello world" of aspect oriented programming. Why aren't you doing logging in an interceptor/aspect? If you did it that way, there'd be no reason for all your classes to implement ILoggable; you could decorate them with logging capability declaratively. I think it's a less invasive design and a better use of interceptors.