2

What is the way to test the methods when there are two public methods and a method calls another public method in the same class?

How should I write unit tests in this scenario?


An example

class SpecificIntMath {
   public int add(int a,int b) {
       return a+b;
   }
   public int multiply(int a, int b) {
       int mul = 0;
       for(int i = 0;i<b,i++) {
           mul=add(a,mul);
       }
       return mul;
   }
}

This example doesn't show the complexity of both the methods involved but the concept.

Should I test add and multiply separately? If I should test multiply only, I feel like we miss out cases where multiple cannot provide parameters.

Assuming multiply and add to be tested separately, should I be able to mock add? How is that possible?

Assuming multiply and add to be tested separately and I shouldn't mock, should I let add perform as it is. If this is the case how should I deal with the flow of the program inside add?

What is the approach to test such a kind of situation.


Edit 1:

In the below code,

class MCVC {
    public boolean getWhereFrom(List<User> users) {
        boolean allDone = true;
        for(User user: users){
            String url = user.getUrl();
            switch(url) {
                case Consts.GOOGLE:
                    someDao.updateFromAddr(user);
                    user.setEntry("Search Engine");
                    break;
                case Consts.FACEBOOK:
                    someDao.updateFromAddr(user);
                    user.setEntry("Social Media");
                    break;
                case Consts.HOME:
                    someDao.updateToAddr(user);
                    user.setEntry("Company");
                default
                    user.setEntry(null);
                    allDone = false;
                    break;
            }
        }
        return allDone;
    }

    public void likedDeck() {
        List<Users> usersList = deckDao.getPotentialUsers(345L,HttpStatus.OK);
        boolean flag = getWhereFrom(usersList);

        if(flag) {
            for(User user: usersList) {
                //some Action
            }
        }
    }
}

Should I consider getWhereFrom() while testing likedDeck() or should I assume any default situation? If I consider default situation, I lose out on cases where the output isn't default. I am not sure I should mock it since class which is calling is being tested. Spying/Mocking class under test

Community
  • 1
  • 1
Tarun Maganti
  • 3,076
  • 2
  • 35
  • 64
  • 1
    Just test them seperately. Donot try to mock `add` when testing `multiply`, you don't even know if `multiply` will call `add` (atleast you are not supposed to know that when writing the test). – john16384 Apr 06 '17 at 11:31
  • Also note that your multiply is broken when b < 0 –  Apr 06 '17 at 11:36

3 Answers3

3

You don't care.

You use unit-testing to test the contract of each public method on its own. Thus you write tests that make sure that both add() and multiply() do what they are supposed to do.

The fact that the one uses the other internally is of no interest on the outside. Your tests should neither know nor care about this internal implementation detail.

And just for the record: as your code is written right now; you absolutely do not turn to mocking here. Mocking is not required here; and only adds the risk of testing something that has nothing to do with your real production code. You only use mocking for situations when you have to control aspects of objects in order to enable testing. But nothing in your example code needs mocking to be tested. And if it would - it would be an indication of poor design/implementation (given the contract of those methods)!

Edit; given the changes example in the question:

First of all, there is a bug in getWhereFrom() - you iterate a list; but you keep overwriting the return value in that list. So when the first iteration sets the result to false; that information might be lost in the next loop.

I see two options for the actual question:

  • You turn to Mockito; and its "spy" concept to do partial mocking; in case you want to keep your source code as is
  • Me, personally; I would rather invest time into improving the production code. It looks to me as getWhereFrom() could be worth its own class (where I would probably not have it work on a list of users; but just one user; that also helps with returning a single boolean value ;-). And when you do that, you can use dependency injection to acquire a (mocked) instance of that "WhereFromService" class.

In other words: the code you are showing could be reworked/refactored; for example to more clearly follow the SRP. But that is of course a larger undertaking; that you need to discuss with the people around you.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • Okay, If I test both separately, then how do I manipulate data inside `multiply` [In my case I have to mock certain `Dao`] the output of which directly affects the internals of `add`? – Tarun Maganti Apr 06 '17 at 12:32
  • I have used DI to push the mock. The problem is that the output of the Dao is a list and the "`add`" method has a `switch-case` and more `Dao` which affect some state and I have to test their arguments. Every Mock is Dependency Injected. – Tarun Maganti Apr 06 '17 at 12:39
  • Cleared the bug. – Tarun Maganti Apr 07 '17 at 07:06
0

At least test them both seperatly. That the multiply test implicitly tests the add is no problem. In most of this cases you should ask yourself the question if it is necessary that both methods need to be public.

Bgvv1983
  • 1,256
  • 1
  • 13
  • 27
0

Should I test add and multiply separately?

You should test them separately, if you are doing unit testing. You would only like to test them together when doing component or integration tests.

Assuming multiply and add to be tested separately, should I be able to mock add?

yes

How is that possible?

use mockito or any other mocking framework. Exactly how you can see here Use Mockito to mock some methods but not others

Assuming multiply and add to be tested separately and I shouldn't mock, should I let add perform as it is.

I wouldn't do that. Internal changes in add could affect the tests from multiply and your tests would get more complicated and unstable.

Community
  • 1
  • 1
Rodolfo
  • 491
  • 5
  • 13