Appropriate encapsulation method for unit testing

My class contains 14 private methods and 1 public method . An open method calls all private methods directly or indirectly using other private methods.

The public method also has a DAO call that queries the database. I wrote a unit test for the class. Since you cannot write unit test for private methods, I changed all private methods to default access and wrote unit test for them.

I was told that I should not change encapsulation for testing purposes only. But my public method has a DAO call and gets its data from the call. Even if I were to write a test for the public method, I assume that it will be very long and difficult.

How do I approach this problem. On the one hand, I have to write a really complex test for a public method that accesses the DAO, and on the other hand, changes the level of access to the methods and creates short, simple testing methods for them. What should I do?

Any suggestions are welcome.

+5
source share
5 answers

Purists will tell you that private methods can be extracted into another helper class that provides accessible methods, and they may be right.

But if it makes sense to store these utility methods inside the class, if the class is not part of the public API and is not intended for a subclass (it may be final, for example), I do not see any problem with some protected or protected private methods. Especially if this non-personal visibility is documented, for example, with the Guava @VisibleForTesting annotation.

+9
source

It looks like you have two problems:

  • How to test private methods (assuming in Java):

    I would look at this question: How to check a class with private methods, fields or inner classes?

    I personally like the answer from Trumpi :

    The best way to test a private method is to use another public method. If this cannot be done, then one of the following conditions is true:

    • Private method is dead code
    • The class you are testing has the smell of design.
    • The method you are trying to test should not be private
  • How to break a DAO dependency

    You can try using Dependency Injection to get rid of your DAO dependency. Then you can make fun of the DAO and enter it into your test case. The advantage is that it really becomes a unit test, not an integration test.

+7
source

If this is difficult, perhaps because your class has more than one responsibility. Usually, when you have private methods that do different things, you can have different classes with public methods that do this for you. Your class will become easier to read, test, and you separate the responsibility. 14 private methods usually indicate such things: P

For example, you might have something like

 public class LeFooService { private final OtherServiceForConversion barService; private final FooDao fooDao; public LeeFooService(FooDao dao, OtherServiceForConversion barService) { this.barService = barService; this.fooDao = dao; } public void createAsFoo(Bar bar) throws ConversionException { Foo foo = convert(bar); fooDao.create(foo); } private Foo convert(Bar bar) { // lots of conversion stuff, services calling D: } } 

for the correct check, you will need to check the correctness of the conversion. Since it is private, you will need to commit the foo sent to FooDao and see if all fields are set correctly. You can use argThat to capture what is sent to FooDao to verify the conversion. Your test will look something like

 .... @Test public void shouldHaveConvertedFooCorrectly() { // given Bar bar = mock(Bar.class); // when fooService.createAsFoo(bar); // then verify(fooDao).create(argThat(fooIsConvertedCorrectly()); } private ArgumentMatcher<Foo> fooIsConvertedCorrectly() { return new ArgumentMatcher<Foo>() { /*test stuff*/ }; } .... 

But if you divided the conversion into another class, for example:

 public class LeFooService { private final BarToFooConverter bar2FooConverter; private final FooDao fooDao; public LeeFooService(FooDao dao, BarToFooConverter bar2FooConverter) { this.bar2FooConverter = bar2FooConverter; this.fooDao = dao; } public void createAsFoo(Bar bar) throws ConversionException { Foo foo = bar2FooConverter.convert(bar); fooDao.create(foo); } } 

you can check what is really important for LeeFooService: call flow. Testing the conversion from foo to Bar will be the answer to unit tests from BarToFooConverter . LeeFooService test example will be

 @RunWith(MockitoJUnitRunner.class) public class LeFooServiceTest { @Mock private FooDao fooDao; @Mock private BarToFooConverter converter; @InjectMocks private LeeFooService service; @Test(expected = ConversionException.class) public void shouldForwardConversionException() { // given given(converter.convert(Mockito.any(Bar.class)) .willThrown(ConversionException.class); // when service.createAsFoo(mock(Bar.class)); // then should have thrown exception } @Test public void shouldCreateConvertedFooAtDatabase() { // given Foo convertedFoo = mock(Foo.class); given(converter.convert(Mockito.any(Bar.class)) .willReturn(convertedFoo); // when service.createAsFoo(mock(Bar.class)); // then verify(fooDao).create(convertedFoo); } } 

Hope this helps :)

Some links that may be helpful:

SOLID

BDD Mockito

+6
source

As a parent would say to his child: DON'T EXPOSE YOUR ACCEPTS!

You do not need to expose your private methods to test them. You can get 100 PERCENT test coverage of your class, including those private methods without exposing them.

The rubbing is that some people believe that the โ€œunitโ€ in unit testing is a function when it really is a class.

For example: I have a class with 1 public method: bool CheckIfPalindrome (string wordToCheck).

Inside, I have private methods for checking the length of a ToCheck word, if it's empty, if it's empty, bla bla bla.

But as a tester, I donโ€™t need to know or care about how I the developer organized (or will organize) the internal code. I am testing an implementation of an interface.

'Given that the word "Mike" when CheckIfPalindronme is called, it should return false "

'Given that the word "Mom", when CheckIfPalindronme is called, it should return true'

'Given that the word "" when CheckIfPalindronme is called, it should return false'

'Given that the word is null when CheckIfPalindronme is called, it should throw an error "

If I consider all possible inputs and expected results, I will test your private functions.

This is the basis of TDD / BDD, without this TDD will not be possible, because we will have to wait and see how you decide to organize your code before we can write our test.

TDD / BDD says you write your tests before you write your code (and it works great, it very quickly identifies flaws in requirements / design)

+3
source

A class containing one public method and 14 private methods is almost impossible to verify. Without seeing him, I would bet that he is very IMPOSSIBLE. As JB Nizet says; my purist colleagues and I will extract most or all of the private methods for helper classes. The reasons are as follows:

  • Ease of testing
  • Easy refactoring
  • Easy to read
  • Easy reuse

Reason not to retrieve: * Many !! classes * It takes time to retrieve * From time to time, performance problems prevent a pretty โ€œrightโ€ design.

IMHO-extraction of logic should always be considered in the case of:

  • Private methods
  • Large classes (I usually start thinking about this when a vertical scrollbar appears in my winow win editor)
  • Loops inside the loop

The keyword here is Single Responsibility (SRP).

+2
source

Source: https://habr.com/ru/post/969400/


All Articles