This question already has answers here:
How do I test a class that has private methods, fields or inner classes?
(58 answers)
Closed 3 years ago.
I am new to JUnit & Mockito, the below class is defined with a method execute which needs to be tested, I wonder is it possible to mock this type of class ? Please shed some light and share your thoughts.
public class MyRule implements SuperRule{
private OrderList orderList;
private ScheduleList scheduleList;
public MyRule (OrderList orderList, ScheduleList scheduleList) {
this.orderList = orderList;
this.scheduleList = scheduleList;
}
#Override
public void execute() {
createWeeklyClassificationRule(orderList);
handle(scheduleList);
}
private void createWeeklyClassificationRule(OrderList orderList) {
//......
}
private void handle(ScheduleList scheduleList) {
//......
}
}
You could mock scheduleList and orderList instead and use verify to make sure the correct methods are being called from them.
public class MyRuleTest
{
private MyRule myRule;
private ScheduleList scheduleListMock;
private OrderList orderListMock;
#Before
public void setUp() throws Exception
{
scheduleListMock = mock(ScheduleList.class);
orderListMock = mock(OrderList.class);
myRule = new MyRule(orderListMock, scheduleListMock);
}
#Test
public void testExecute()
{
myRule.execute();
verify(scheduleListMock).foo();
verify(orderListMock).bar();
}
...
You would just replace foo and bar with whatever methods you are expecting to be called.
If you are testing MyRule, you shouldn't be mocking it. A good rule of thumb is to not mock the class that is under test.
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 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
This question already has answers here:
Test class with a new() call in it with Mockito
(7 answers)
Closed 5 years ago.
This is not a duplicate of Test class with a new() call in it with Mockito. I'm trying to write a test to verify that certain methods are being called within the constructor of my spy object (mockToyFacade).
The class under test is ToyFactoryFacade. The idea is clients interact with the ToyFactoryFacade (which wraps a ToyFactory) to generate ToyFacades, which itself is a wrapper around the Toy object.
What I am trying to verify with Mockito?
I want to verify that addToyName(toyName) and addCreationTime(creationTimestamp) are being called on the ToyFacade. Both of these methods are called in the constructor of the ToyFacade.
What's the issue?
When I try to spy the ToyFacade, and verify that both aforementioned methods are called, I receive an error, which says "Actually, there were zero interactions with this mock." When I call the methods separately (i.e., not via the constructor), the verification check out correctly. I'm not sure what I'm doing incorrectly.
Test Code
public class ToyFactoryFacadeTest {
private Toy mockToy;
private ToyFacade mockToyFacade;
// System under test.
private ToyFactoryFacade toyFactoryFacade;
private ToyFactory mockToyFactory;
#Before
public void setup() {
mockToy = mock(Toy.class);
mockToyFacade = spy(new ToyFacade(mockToy, "Phone", System.currentTimeMillis()));
mockToyFactory = mock(ToyFactory.class);
toyFactoryFacade = new ToyFactoryFacade(mockToyFactory) {
#Override
public Toy getToyFacade(String toyName, long creationTimestamp){
return mockToyFacade;
}
};
}
#Test
public void testToyFactoryFacade() {
toyFactoryFacade.initializeAndGetToy("Phone", System.currentTimeMillis());
verify(mockToyFacade).addToyName("Phone");
verify(mockToyFacade).addCreationTime(anyLong());
}
}
Source Code
public class ToyFactoryFacade {
private final ToyFactory toyFactory;
public ToyFactoryFacade(ToyFactory toyFactory) {
this.toyFactory = toyFactory;
}
public ToyFacade initializeAndGetToy(String toyName, long creationTimestamp)
{
getToyFacade(toyName, creationTimestamp);
}
// For testing.
protected ToyFacade getToyFacade(String toyName, long creationTimestamp
{
return new ToyFacade(toyFactory.newToy(), toyName, creationTimestamp);
}
}
public class ToyFactory {
public Toy newToy() {
return new Toy();
}
}
public class ToyFacade {
private final Toy toy;
public ToyFacade(Toy toy, String toyName, long creationTimeStamp) {
this.toy = toy;
addToyName(toyName);
addCreationTime(creationTimestamp);
}
public void addToyName(String name) {
toy.addToyName(toyName);
}
public void addCreationTime(long timestamp) {
toy.addCreationTime(timestamp);
}
}
public class Toy {
public String toyName;
public String creationTimestamp;
public void addToyName(String name) {
toyName = name;
}
public void addCreationTime(long timestamp) {
creationTimestamp = timestamp;
}
}
Your test isn't doing what you expect because the method calls that you're trying to verify have already taken place before you create your spy. What you really want to do is to test the effect of those two method calls, rather than the calls themselves. This would look something like
verify(mockToy).addToyName("Phone");
verify(mockToy).addCreationTime(timestamp);
where timestamp is whatever you pass in in the setUp method.
I have the following test set up. I don't understand how the test is passing successfully since the user is set to "Dummy."
#RunWith(MockitoJUnitRunner.class)
public class TodoServiceAbstractImplTest
{
#InjectMocks
TodoServiceAbstractImpl todoServiceAbstractImpl = new TodoServiceAbstractImpl();
#Mock
SomeRandomClass someRandomClass;
#Mock
TodoServiceAbstract todoServiceAbstract;
#Test
public void testRetrieveTodo_usingAMock(){
todoServiceAbstractImpl.setUser("Dummy"); //Set the user to be "Dummy" already
assertEquals(null,todoServiceAbstractImpl.getUser()); //Why is the user is still null?
}
}
Here are the relevant classes. I created them to test Mockito as I am still learning testing in Spring Boot.
Definition of the SomeRandomClass:
public class SomeRandomClass{
private String field;
public SomeRandomClass(){
}
public SomeRandomClass(String field){
setRandom(field);
}
public void setRandom(String field){
this.field = field;
}
public String getRandom(){
return field;
}
}
Definition of the Abstract class:
public abstract class TodoServiceAbstract {
#Autowired
private SomeRandomClass RandomUser;
public TodoServiceAbstract(){
//RandomUser = new SomeRandomClass();
}
public void setUser(String user){
this.RandomUser.setRandom(user);
}
public String getUser(){
return RandomUser.getRandom();
}
public abstract List<String> retrieveTodos(String user);
}
Definition of the Abstract Implementation
public class TodoServiceAbstractImpl extends TodoServiceAbstract{
public List<String> retrieveTodos(String user){
if(user == getUser()){
return Arrays.asList("item 1", "item 2",
"item 3");
}
return Arrays.asList("Random item");
}
}
Tom answered in the comments:
Why do you expect something else than null? SomeRandomClass is mocked so it obviously doesn't actually set anything when calling setUser. And why should it? That's the point of a mock.
Remember that mocked implementations are not real, and in particular unstubbed calls will return dummy values such as null, 0, or an empty string.
In addition to what Tom already said in the comments, this test is testing your mocks, rather than your actual implementation. Since you mocked SomeRandomClass, your tests should verify if that method is being called. In this case you should test if SomeRandomClass.setRandom() is called when you call setUser() and likewise, you should test if SomeRandomClass.getRandom() is called when you call getUser().
For example:
#Test
public void getUser_shouldUseGetRandom() {
when(someRandomClass.getRandom()).thenReturn("data");
assertEquals("data", todoServiceAbstractImpl.getUser());
}
To test setUser() you can do something like:
#Test
public void setUser_shouldUseSetRandom() {
todoServiceAbstractImpl.setUser("data");
verify(someRandomClass).setRandom("data");
}
By mocking/stubbing you can write proper unit tests for TodoServiceAbstractImpl without having to take the behaviour of SomeRandomClass.