0

I have implemented a method getUsers(), which basically construct a List<ShoppingCart>, then create a List<User>:

public List<User> getUsers() {
   // construct a liste of List<ShoppingCart>
   ....
   // update 
   ...
}

The construction of List<ShoppingCart> contains a lot of logic, so I decided to move those code out and create a private method:

public List<User> getUsers() {
   // construct a liste of List<ShoppingCart>
   List<ShoppingCart> shoppingList = getShoppingList();
   // update 
   ...
}

private List<ShoppingCart> getShoppingList() {
  ...
}

Now I need to unit test getUsers(). But I realized that I have difficulty to get the List<ShoppingCart> because it's a private method. And I don't want to make getShoppingList() public because I don't need it anywhere else.

I think there is a design problem in my code, what is the best way to unit test these kinds of methods containing returned value of private methods ?

Thanks.

UPDATE

No it's not the same question as Java test class with many private methods, my question is not if it's necessary to test private method, but what should be a better design

hawarden_
  • 1,904
  • 5
  • 28
  • 48

3 Answers3

3

I think good option is separate logic for user and shopping cards. If You agree with me, You can move shopping cards logic to different class, and then You can mock this logic on Your test and then write test for getUsers() like this:

public class UserTest {

 @Mock
 private ShoppingCard shoppingCard;
 private User sut = new User();

 @Before
 public void setUp(){
    MockitoAnnotations.initMocks(this);
 }


 @Test
 public void shouldReturnUsersEmptyListWhenCardsEmpty(){
    //given
    when(shoppingCard.getShoppingCards()).thenReturn(Collections.emptyList());

    //when
    final List<User> result = sut.getUsers();

    //then
    assertEquals(0, result.size());
 }
}
MatWdo
  • 1,610
  • 1
  • 13
  • 26
2

In the end, this is about balancing "purity" against, well, the "real world"?!

Meaning: if you insist on having a private method, then that prevents you from doing partial mocking for example. And it prevents you from directly testing the method.

Personally, I sometimes go pragmatic in such situations: simply by making that other method package protected (instead of private). Then you can access it from unit tests, and when necessary, use a Mockito spy to partially mock out such methods.

The "real world" design solution: consider if "getting the shopping list" isn't something that is worth to stand completely on its own. Actually, it sounds rather odd that such a "complex" activity ... sits somewhere as a private method. The consequence of doing so might be: you start duplicating code. If there is one central service (class) that gets you "the shopping list", then any code that needs that list ... can get it from there.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
0

If a method should be private, it shouldn't be unit tested. This leaves you with 2 options:

  • Make getShoppingList() public
  • Don't unit test getShoppingList()

If the correctness of getShoppingList() is fundamentally required for your entire application to work, you should make it public and create unit tests for it.

If, however, it is only called by code that then processes it, and those methods are user-facing, you can simply test those methods and ensure they behave as expected. This then passively guarantees that getShoppingList() works as expected.

Imagine you had an error that made getShoppingList() throw some kind of exception. Then, in your test for getUsers() you should see that exception thrown anyway (assuming it calls getShoppingList().

cameron1024
  • 9,083
  • 2
  • 16
  • 36