I'm pretty new in unit testing and dont know how to test the following circunstances over a callback for this example class:
public class Foo {
private final ItemLoader loader;
private Bar bar;
public Foo(ItemLoader loader,Bar bar) {
super();
this.loader = loader;
this.bar=bar;
}
public void getItems(ItemStore.Callback callback) {
List<ItemData> itemData = bar.getItemData();
List<Item> items = this.loader.transform(itemData);
callback.onItemsLoaded(items);
}
}
That callback.onItemsLoaded is called with the result of loader.transform
My current test is:
public class ExampleTest extends BaseTestCase {
private Foo foo;
#Mock
private Bar mockBar;
#Mock
private ItemLoader mockItemLoader;
#Mock
private ItemStore.Callback itemLoadCallback;
public void setUp() {
MockitoAnnotations.initMocks(this);
foo = new Foo(mockItemLoader, mockBar);
}
public void testGetItems() {
List<ItemData> mockItemData = (List<ItemData>) mock(List.class);
when(mockBar.getItemData()).thenReturn(mockItemData);
foo.getItems(itemLoadCallback);
verify(mockItemLoader).transform(mockItemData);
}
}
It tests:
That loader.transform is called
That callback.onItemsLoaded is called
But I realised that if I change the last line of the Foo.getItems method like (Notice the null):
public void getItems(ItemStore.Callback callback) {
...
callback.onItemsLoaded(null);
}
The test keep pasing. So I'd need to test that callback.onItemsLoaded is called with the result of loader.transform
So I modified the test:
public void testGetItems() {
List<ItemData> mockItemData = (List<ItemData>) mock(List.class);
when(mockBar.getItemData()).thenReturn(mockItemData);
foo.getItems(itemLoadCallback);
verify(mockItemLoader).transform(mockItemData);
List<Item> resultItems = verify(mockItemLoader).transform(mockItemData);
verify(itemLoadCallback).onItemsLoaded(resultItems);
}
But it complains in the last line saying Argument(s) are different!
How can I fix the test
Because mockItemLoader is a mock, it will actually return an empty list from transform. If you want to make it return something different, you could set up an object for it to return. Basically, this will be your own List<Item>. So you can then stub the tranform method instead of verifying it; and use the same List<Item> when you verify the call to onItemsLoaded.
Related
I am testig a public method and I want to verify if a private method, that have mocked params, is called.
All the answers I have found are using invoke method, but this was removed since JMockit v1.36
public class ClassToTest{
public void methodToTest(){
DependencyClass abc = new DependencyClass();
if(privateMethod1()){
privateMethod2(abc);
}
}
private boolean privateMethod1(){ return true; }
private void privateMethod2(DependencyClass abc){ abc.doStuff(); }
}
public class testClassToTest{
#Mocked
DependencyClass abc;
#Tested
ClassToTest testedClass;
#BeforeEach
public void setUp() {
testedClass = new ClassToTest();
}
#Test
public void testMethod(){
new MockUp<ClassToTest>() {
#Mock
private boolean privateMethod1() {
return true;
}
};
testedClass.methodToTest();
new FullVerificationsInOrder() {{
abc = new DependencyClass();
//Check here if privateMethod2(abc) gets called once
}};
}
You can use Powermock to mock and verify private methods.
Please check https://github.com/powermock/powermock/wiki/MockPrivate
You have two ways:
To level up your method's scope from private to package-private and after it, your method will become visible in the test.
Refactoring your code and encapsulate the private method to Predicate and after it, you can test your primary method and Predicate separately.
You can't test the private method by Junit.
How to test void methods in Mockito with assertSame or assertEquals. I am able to do verify only.
i am getting sonar or PMD rules violation -"JUnit tests should include assert() or fail()".
Below is my sample class with test class.
#Service
public class MyServiceImpl implements IService {
#Autowired
private IDyDBDAO dyDBDAO;
#Override
public void update() {
dyDBDAO.save(getDetailData());
}
#Override
public List<Detail> getCurrentDetail() {
return getDetails(dyDBDAO.findAll());
}
private List<Detail> getDetails(Iterable<Detail> details) {
...blah...
}
private String getPlace(){
Places p = Places.getPlace();//static
return p == null? PlacesUtil.getName("DH"): p.getName;
}
private Detail getDetailData() {
Detail d = new Detail();
d.setName("blah");
d.setDesc("fsdfsdfdsf");
d.setPlace(getPlace());
return d;
}
}
#RunWith(PowerMockRunner.class)
#PrepareForTest({Places.class, PlacesUtil.class})
public class MyServiceImplTest {
#InjectMocks
private MyServiceImpl myServiceImpl;
#Mock
private IDyDBDAO dyDBDAO;
#Test
public void testGetCurrentDetail() {
given(dyDBDAO.findAll()).willReturn(getMockDetails());
assertSame(myServiceImpl.getCurrentDetail().size(), 2);
}
#Test
public void testUpdate() {
PowerMockito.mockStatic(Places.class);
// first update , second update -us-west-2 will update
given(Places.getPlace()).willReturn(PlacesUtil.getName("UH"))
.willReturn(null);
myServiceImpl.syncStatus();
// update again with DH
myServiceImpl.syncStatus();
verify(dyDBDAO, times(2)).save(any(Detail.class));
// how to assert checking here
}
private Iterable<Detail> getMockDetails() {
Detail d1 = new Detail();
d1.setName("blah");
d1.setDesc("fsdfsdfdsf");
d1.setPlace("sdfsdf");
Detail d2 = new Detail();
d2.setName("blahblah1");
d2.setDesc("e345345");
d2.setPlace("8907j");
List<Detail> listOfDetail = new ArrayList<>();
listOfDetail.add(eps1);
listOfDetail.add(eps2);
return listOfDetail;
}
}
You need to capture the value passed to the dao save method. Use mockito's ArgumentCaptor for that. Then assert on that value.
Something along these lines:
ArgumentCaptor<Detail> captor = ArgumentCaptor.forClass(Detail.class);
verify(dyDBDAO, times(2)).save(captor.capture());
Detail detail1 = captor.getValues().get(0)
assertEquals(expectedDetail, detail1)
I would assume that your void method that needs to be tested is update in MyServiceImpl.
Firstly, you can verify if dyDBDAO.save() is called.
Mockito.verify(dyDBDAO).save(Mockito.anyList...);
Secondly, you can check the modified or created records in the database by retrieving them and comparing to the inputs from getMockDetails.
I am trying to use argument capture to determine what arguments are being passed to a mocked Mockito method, but I am not able to capture any values.
class CombinedEvent
{
final List<String> events;
public CombinedEvent() {
this.events = new ArrayList<>();
this.events.add("WATCHITM");
this.events.add("BIDITEM");
}
}
Holder class
class CombinedNotificationAdapter {
private CombinedEvent combinedEvent;
CombinedNotificationAdapter() {
this.combinedEvent = new CombinedEvent();
}
public boolean isEnabled(String user, NotificationPreferenceManager preferenceManager) {
boolean status = true;
for (String event : combinedEvent.events) {
status = status && preferenceManager.isEventEnabled(user, event);
}
return status;
}
}
My unit test
#RunWith(JUnit4.class)
class CombinedNotificationAdapterTest {
private CombinedNotificationAdapter adapter;
#Mock
private NotificationPreferenceManager preferenceManager;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
adapter = new CombinedNotificationAdapter();
}
#Test
public void testIsEnabled() {
doReturn(true).when(preferenceManager).isEventEnabled(eq("test"), anyString());
Assert.assertTrue(adapter.isEnabled("test", preferenceManager));
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
verify(preferenceManager, times(2)).isEventEnabled(eq("test"), captor.capture());
System.out.println(captor.getAllValues());
}
}
The output of captor.getAllValues() is an empty list. I would like the values to return a list of WATCHITM and BIDITEM. I don't know what I am going wrong.
Reference:
https://static.javadoc.io/org.mockito/mockito-core/2.28.2/org/mockito/Mockito.html#15
https://static.javadoc.io/org.mockito/mockito-core/2.6.9/org/mockito/ArgumentCaptor.html
I think you are overdoing:
doReturn(true)
. when(preferenceManager)
.isEventEnabled(eq("test"), anyString()):
You are scrubbing that expected method invocation and then combining that with your argument captor. And that does not work. You can either stub or capture, not both things! See this existing question for example.
My suggestion: look at this answer and learn how to create your own Answer object. Those get passed an instance of InvocationOnMock. And that class allows you to check the arguments passed into the mocked calls, too!
I am making a unit test for class in my app, it just a simple class and I thought i did everything right but the test failed saying
Wanted but not invoked:
mContextWeakReference.get();
-> at rahmat.com.app.utility.backwardcompatibility.StringResourceUtilTest.getString(StringResourceUtilTest.java:40)
Actually, there were zero interactions with this mock.
this is the class to be tested
public class StringResourceUtil {
private static StringResourceUtil sInstance;
private WeakReference<Context> mContextWeakReference;
public static StringResourceUtil getInstance() {
return sInstance;
}
#Inject
public StringResourceUtil(Context context) {
mContextWeakReference = new WeakReference<>(context);
sInstance = this; //NOSONAR
}
public String getString(int resId) {
return mContextWeakReference.get().getString(resId);
}}
this is unit test I made
public class StringResourceUtilTest {
private StringResourceUtil mResourceUtil;
#Mock
private Context mContext;
#Mock
private WeakReference<Context> mContextWeakReference;
#Before
public void setUp(){
MockitoAnnotations.initMocks(this);
mResourceUtil = new StringResourceUtil(mContext);
}
#Test
public void getString() {
int resId = 123;
mResourceUtil.getString(resId);
verify(mContextWeakReference).get().getString(eq(resId));
}}
any help would be much appreciated, thanks
Your StringUtil class is always creating a new object of mContextWeakReference object and even if you are making it, it won't inject automatically ( for that you use injectMock but no use here, since new object creation always happens internally).
public class StringResourceUtilTest {
private StringResourceUtil mResourceUtil;
#Mock
private Context mContext;
#Before
public void setUp(){
MockitoAnnotations.initMocks(this);
mResourceUtil = new StringResourceUtil(mContext);
// setup mock return type
// mock objects are not real,so need to moeck the behavior of method as well
when(mContext.getString(R.string.a123)).thenReturn("123");
}
#Test
public void getString() {
int resId = R.string.a123;
// check the return type
assertEquals("123",mResourceUtil.getString(resId));
}
}
Note: To verify the internal working, read
What is the difference between mocking and spying when using Mockito?
Because you creating mContextWeakReference = new WeakReference<>(context); in constructor, it will never been a mock in StringResourceUtil.
You can set prepared mock mContextWeakReference by using
org.springframework.test.util.ReflectionTestUtils.setField(mResourceUtil , "mContextWeakReference", mContextWeakReference);
Otherwise you should modifying StringResourceUtil class to be a testable
I would like to write unit tests for a singleton class, but this class have dependencies to ui components. The class is PageManager and have some functionality to go back and go forward in the page history. With a unit test I like to test this history functionality but I don't want to initialize the ui stuff, becouse it is not needed for this test.
I'am new to JMockit and I tryed this out, but wihtout success:
Here is the original class to be mocked:
public final class PageManager {
private static final PageManager INSTANCE = new PageManager();
private final Set<Page> pages = new HashSet<>();
private Page currentPage;
private boolean initialized = false;
private PageManager() {
// Do some UI stuff
}
public static PageManager getInstance() {
return INSTANCE;
}
public void addPage(final Page page) {
pages.add(page);
}
public void initialize() {
// Do some UI stuff
initialized = true;
}
public Page getPage() { return currentPage; }
public void setPage(final Page page) { ... }
public void goBack() { ... };
public void goForward() { ... };
public boolean canGoBack() { ... };
public boolean canGoForward() { ... };
private void activatePage(final Page page) {
// Do some UI stuff
this.currentPage = page;
}
private void deactivatePage(final Page page) {
// Do some UI stuff
}
}
This is the mocked version:
public final class MockedPageManager extends MockUp<PageManager> {
PageManager instance;
#Mock
void $init(final Invocation invocation) {
instance = invocation.getInvokedInstance();
}
#Mock
void initialize() {
// Don't do UI stuff
Deencapsulation.setField(instance, "initialized", true);
}
#Mock
void activatePage(Page page) {
Deencapsulation.setField(instance, "currentPage", page);
page.activate();
}
#Mock
void deactivatePage(Page page) {
}
}
And a small test:
#Test
public void testGoBack() {
new MockedPageManager();
final Page p1 = new Page() { #Override public String getTitle() { return "p1"; } };
final Page p2 = new Page() { #Override public String getTitle() { return "p2"; } };
final PageManager pm = PageManager.getInstance();
pm.addPage(p1);
pm.addPage(p2);
pm.initialize();
pm.setPage(p1)
assertEquals(p1, pm.getCurrentPage());
pm.setPage(p2);
assertEquals(p2, pm.getCurrentPage())
assertTrue(pm.canGoBack());
pm.goBack();
assertEquals(p1, pm.getCurrentPage());
}
In this test, the $init method get invoked by JMockit correctly. The problem is, that an NullPointerExceptions is thrown in the test when pm.addPage(p1) is called. The stacktrace says, that the NPE occurs in the original class PageManager becouse the field Set pages is null.
My question is: Is this singleton class correctly mocked? Does the $init method override only the constructor or also the Java instance initializer i.e. Set pages = new HashSet<>();
As stated here, instance initializing blocks or statements are copied into each constructor (by the compiler). I suspect that JMockit uses reflection/byte code manipulation to mock the class's constructor, effectively circumventing all of the initializing code. Therefore the initializers are not executed and the set variable remains null. If you really have to make this work, try to initialize it properly in the mock. Better yet, refactor your class to allow its use in tests (e.g. an additional package private constructor for testing with injected dependencies; or move the page history functionality to its own class).