I wrote the test which uses BBDMockito and Argument Captor. Argument Captor is used only to capture callback and invoke onDataNotAvailable(), not for the verification.
#Test
public void loadNoItemFromRepository_showsMissingItem() {
//given
itemDetailPresenter = new ItemDetailPresenter(UNCHECKED_ITEM.getId(), itemsRepository, itemDetailView);
given(itemDetailView.isActive()).willReturn(true);
//when
itemDetailPresenter.load();
verify(itemsRepository).getItem(eq(UNCHECKED_ITEM.getId()), getItemCallbackArgumentCaptor.capture());
getItemCallbackArgumentCaptor.getValue().onDataNotAvailable();
//then
then(itemDetailView).should().showMissingItem();
}
Verify placed in //when section is confusing because the name suggests it should be placed in the verification section (//then). Is there an alias for verify() so I can use it with argument captor and the name will be more appropriate for //when?
Edited:
The code which I want to test is if itemDetailView.showMissingItem() was called.
public void load() {
(...)
itemsRepository.getItem(itemId, new ItemsDataSource.GetItemCallback() {
#Override
public void onItemLoaded(Item item) {
(...)
if (nonNull(item))
showItem(item);
else
itemDetailView.showMissingItem();
}
#Override
public void onDataNotAvailable() {
(...)
itemDetailView.showMissingItem();
}
});
}
verify(...) is an assertion, it's used to check a method was/wasn't called and how many times - it belongs in the //then section
I see you're also using an argumentCaptor but aren't checking anything with it, the proper process there would be to assert that the captured value (getItemCallbackArgumentCapture.getValue() contains/equals a value you expect).
Related
I am trying to test a void method such as following:
#Override
public void onApplicationEvent(ApplicationEvent myEvent) {
if (myEvent instanceof ApplicationEnvironmentPreparedEvent) {
ConfigurableEnvironment myEnv= ((ApplicationEnvironmentPreparedEvent) myEvent).getEnvironment();
setSystemVariables(myEnv);
}
}
I am using Matchers and here is the unit test (which obviously is not testing anything)
#Test
public void testOnApplicationEvent() {
loggingListener.onApplicationEvent(any(ApplicationEnvironmentPreparedEvent.class));
}
Two issues:
1. The error I get from the build is "Invalid use of Matchers" and test doesn't pass in my Jenkins build (but passes in idea IDE)
2. How to test these methods to keep the test coverage percentage up to a desired level
1 - This issue because any is used incorrectly. Refer the Mockito guide for details. Below my example does not use any and the problem will be gone.
2 - To cover 2 branches of if I would recommend below test cases.
#Test
public void onApplicationEventShouldSetEnvironmentWhenApplicationEnvironmentPreparedEvent() {
ConfigurableEnvironment actualEnvironment = null;
// Given a listener with overridden setSystemVariables() to store passed env.
LoggingListener loggingListener = new LoggingListener() {
#Override
void setSystemVariables(ConfigurableEnvironment var){
actualEnvironment = var;
}
};
// Given some dummy environment which is delivered by an event.
ConfigurableEnvironment expectedEnvironment = new ConfigurableEnvironment();
// Given a mocked event with above dummy environment.
ApplicationEvent mockedEvent = Mockito(ApplicationEnvironmentPreparedEvent.class);
Mockito.when(mockedEvent.getEnvironment()).returns(expectedEnvironment);
// When call a method under test
loggingListener.onApplicationEvent(mockedEvent);
// Then make sure the given environment was passed and set correctly
assertSame(expectedEnvironment, actualEnvironment);
}
#Test
public void onApplicationEventShouldSkipNotApplicationEnvironmentPreparedEvent() {
// Given a listener with overridden setSystemVariables() to fail the test if called.
LoggingListener loggingListener = new LoggingListener() {
#Override
void setSystemVariables(ConfigurableEnvironment var){
fail("This method should not be called");
}
};
// Given a mocked other (not ApplicationEnvironmentPreparedEvent) event.
ApplicationEvent mockedEvent = Mockito(UnknownEvent.class);
// When call a method under test
loggingListener.onApplicationEvent(mockedEvent);
// Then make sure an environment was not asked at all.
Mockito.verify(mockedEvent.getEnvironment(), never);
}
Note, this is not compilable code, because I don't know your full production code, so treat this as an idea to apply it on your real code with corresponding modifications.
Here is my test method where It should be success if showLoading() and loadDataSuccess(response) was called:
#RunWith(PowerMockRunner.class)
public class PresenterTest {
#Mock
private ProfileContract.View view;
#Mock
private ProfileContract.Handler handler;
#Test
public void onLoadDataClicked() {
presenter.loadData();
verify(mView, times(1)).showLoading();
verify(mHandler, times(1)).loadDataSuccess();
}
}
UPDATE 1
Here is my presenter:
class ProfilePresenter(private val mView: ProfileContract.View) : ProfileContract.Handler {
override fun loadData() {
mView.showLoading()
mUserService.user()
.compose(RxUtil.mapper())
.subscribe({ response ->
loadDataSuccess()
}, { error ->
//stuff
})
}
}
Thanks!
If you use return statment, your test finish with success status.
I think there is a basic problem with your test setup:
You do not use verify to check if one function calles another function within the same class. Verify is used to verify that the tested class calls function on other (mocked) classes. If I am not mistaken, your setup should actually give you an error message saying that you can not use verify on instantiated classes.
What you should do -if you want to check if onCompleteClicked() produces the correct results- is to check if the data that gets changed inside the onStuffComplete() function is set correctly. You can use an assert for that.
As an example, lets say onStuffCompleted() sets completeCounter to 1
#Test
public void onCompleteClicked() {
presenter.onStuffCompleteClicked();
assertEquals(completCounter , 1);
}
And to answer your original question: verify (and assert) will pass if the requirements were met (and by this the whole test will pass) and fail if not. You do not need to add any additional stuff (but once again: verify will only work with mocked classes).
I have a method (method1) that I'd like to test, which based on parameters provided creates an object and calls another method (method2). So I'm mocking method2, which accepts an object (sampleObj).
public void method1(booleanParam) {
if(booleanParam){
List<SampleObj> fooList = new ArrayList<SampleObj>;
fooList.add(new SampleObj("another param"));
anotherService.method2(fooList);
}
//some other smart logic here
}
And here's my test with same obfuscated names (sorry if I missed any typo):
public void testMethod1() {
AnotherService mockedAnotherService = PowerMockito.mock(AnotherService.class);
ServicesFactory.getInstance().setMock(AnotherService.class, mockedAnotherService);
List<SampleObj> fooList = new ArrayList<SampleObj>;
fooList.add(new SampleObj("another param"));
// assert and verify
service.method1(true);
Mockito.verify(mockedAnotherService, times(1)).method2(fooList);
}
The problem is, when I try to mock the anotherService, I need to pass an object to method2, so I have to create a new one. But since it's a new object, it's not the same object, which will be passed from inside the method1, hence the test fails with the exception:
Argument(s) are different! Wanted:
anotherService.method2(
[com.smart.company.SampleObj#19c59e46]
);
-> at <test filename and line # here>
Actual invocation has different arguments:
anotherService.method2(
[com.smart.company.SampleObj#7d1a12e1]
);
-> at <service filename and line # here>
Any ideas how to accomplish that?
You have a few options:
Implement equals and hashCode on SampleObj. Because you didn't wrap fooList in a matcher, Mockito checks with List.equals, which checks equals for corresponding objects in each List. The default behavior of Object.equals is that a.equals(b) iff a == b--that is, objects are equal iff they refer to the same instance--but you're welcome to override that if every SampleObj("foobar") equals every other SampleObj("foobar").
Use a Hamcrest Matcher you write.
private static Matcher<List<SampleObj>> isAListWithObjs(String... strings) {
return new AbstractMatcher<List<SampleObj>>() {
#Override public boolean matches(Object object) {
// return true if object is a list of SampleObj corresponding to strings
}
};
}
// in your test
verify(mockedAnotherService).method2(argThat(isAnObjListWith("another param")));
Note that you could also just make a Matcher of a single SampleObj, and then use a Hamcrest wrapper like hasItem. See more matchers here.
Use a Captor to check equals your own way:
public class YourTest {
// Populated with MockitoAnnotations.initMocks(this).
// You can also use ArgumentCaptor.forClass(...), but with generics trouble.
#Captor ArgumentCaptor<List<SampleObj>> sampleObjListCaptor;
#Test public void testMethod1() {
// ...
verify(mockedAnotherService).method2(sampleObjListCaptor.capture());
List<SampleObj> sampleObjList = sampleObjListCaptor.getValue();
assertEquals(1, sampleObjList.size());
assertEquals("another param", sampleObjList.get(0).getTitle());
}
I have a code which interacts with some object and then should call finish() method on it.
void completeTransaction(PaymentTransaction transaction) {
recordTransaction(transaction.getId());
transaction.finish();
}
PaymentTransaction is some third-party class which behaviour after finish() is undefined — it may throw an exception or just fail silently.
I need to write a unit test which passes then and only then:
recordTransaction(transaction.getId()) called
transaction.finish() called
transaction.finish() called after recordTransaction(transaction.getId())
Test satisfying the above conditions should prohibit code like this:
void completeTransaction(PaymentTransaction transaction) {
transaction.finish();
recordTransaction(transaction.getId()); //oops
}
Test case for the first condition:
void testCompleteTransaction_TransactionRecorded() {
completeTransaction(transactionMock);
// assert that recordTransaction(transaction.getId())
// called with correct argument
completeTransaction(PaymentTransaction transaction)
}
For the second one:
void testCompleteTransaction_TransactionCompleted() {
completeTransaction(transactionMock);
// assert that transaction.finish() called
}
I wonder how can I enforce the 3rd condition via test case.
You could pass in a fake PaymentTransaction that overrides finish() and getId() such that finish() throws an exception if some internal flag isn't set when getId() is called.
public class FakePaymentTransaction {
private bool _getIdWasCalled = false;
public override void finish () {
if (!_getIdWasCalled) {
throw new Exception ("getId wasn't called first!");
}
}
public override /* your return type */ getId() {
_getIdWasCalled = true;
// Some other logic to return your specified return type
}
}
Now when you pass it into your SUT, you will see if the calls were made in the right order.
What you want is a mock that can verify the order of calls was as expected. You can roll your own for the specific case as suggested in James D'Angelo's answer or you could create a more generic one that works similarly.
Or you can use facilities supplied by a good mocking framework.
Mockito has, for example, an InOrder verifier that can verify the order of calls of mocked methods from a single mock or multiple mocks.
Your test case makes no sense:
Methods are called in the order you have them in the code:
In an Unit test you should not only call some methods, you should test for a correct result.
but if you want to have some fun:
public testNonsenseTest() {
int i = 0;
PaymentTransaction transaction = new PaymentTransaction();
int transactionId = transaction.getId());
recordTransaction(transactionId);
i++;
assertEquals(1, i);
transaction.finish();
i++;
assertEquals(2, i);
}
I am trying to test a class similar to the example below:
public class Service : IService
{
public string A(string input)
{
int attemptCount = 5;
while (attemptCount > 0)
{
try
{
return TryA(input);
}
catch (ArgumentOutOfRangeException)
{
attemptCount--;
if (attemptCount == 0)
{
throw;
}
// Attempt 5 more times
Thread.Sleep(1000);
}
}
throw new ArgumentOutOfRangeException();
}
public string TryA(string input)
{
// try actions, if fail will throw ArgumentOutOfRangeException
}
}
[TestMethod]
public void Makes_5_Attempts()
{
// Arrange
var _service = MockRepository.GeneratePartialMock<Service>();
_service.Expect(x=>x.TryA(Arg<string>.Is.Anything)).IgnoreArguments().Throw(new ArgumentOutOfRangeException());
// Act
Action act = () => _service.A("");
// Assert
// Assert TryA is attempted to be called 5 times
_service.AssertWasCalled(x => x.TryA(Arg<string>.Is.Anything), opt => opt.Repeat.Times(5));
// Assert the Exception is eventually thrown
act.ShouldThrow<ArgumentOutOfRangeException>();
}
The partial mocking doesn't seem to accept my expectation. When I run the test I receive an error about the input. When I debug, I see that the actual implementation of the method is being executed instead of the expectation.
Am I doing this test correctly? According to the documentation ( http://ayende.com/wiki/Rhino%20Mocks%20Partial%20Mocks.ashx ): "A partial mock will call the method defined on the class unless you define an expectation for that method. If you have defined an expectation, it will use the normal rules for this."
It's is important to note that mocking frameworks like Rhinomocks, Moq and NSubstitute use a feature in .NET called DynamicProxy that dynamically generates a derived class of the mock in memory. Classes must:
be an interface; or
non-sealed class with parameterless constructor; or
derive from MarshalByRefObject (moq has moved away from this feature)
Methods must be part of the interface or made virtual so that alternate behaviors can be substituted at runtime.