How is Unit Test this (use mocks or classic unit test?)

I need to write a JUnit test for the following (simplified) method:

/** Return name of previous entry or name of given entry if no previous entry. */ public String getPreviousName(TreeEntry entry) { if (entry.getPrevious() != null) { return entry.getPrevious().getName(); } else { return entry.getName(); } } 

I just don't know how I should check this out. I could either

a) Use Mocks to grind the parameter and its previous record or

b) Create a real TreeEntry and a real previous record

The problem with using mocks is that I have to say in the test case which method the actual implementation should use, for example. here I say that the correct name is obtained through getPrevious () TreeEntry, and then through getName () of this previous record (without considering the case if null, because this is basically not a problem):

 TreeEntry mockEntry = mock(TreeEntry.class); TreeEntry mockPreviousEntry = mock(TreeEntry.class); when(mockEntry.getPrevious()).thenReturn(mockPreviousEntry); when(mockPreviousEntry.getName()).thenReturn("testName"); assertEquals("testName", classUnderTest.getPreviousName(mockEntry)); 

But a developer can, for example, implement it like this:

 return NameService.getName(entry.getPrevious()); 

It just doesn't matter for the test.

However, if I use classic unit testing without layouts, I have another problem. The TreeEntry constructor is very complex. It has 5 parameters that need valid objects. Therefore, it is very difficult to create something like:

 TreeEntry entry = new TreeEntry(...); TreeEntry previousEntry = new TreeEntry(...); entry.setPrevious(previousEntry); previousEntry.setName("testName"); assertEquals("testName", classUnderTest.getPreviousName(entry)); 

The code will be much longer than this, because the constructors take complex parameters. Another thing is that the designer refers to the file system to load its contents from there, so it adds to the slowdown of the modules.

Using the classic approach, it also ties the test a lot more to the TreeEntry implementation. Because if something has changed in TreeEntry with the constructors or setting up the previous record, it will also need to be changed in the test. And if he forgets, this will cause the test to fail even hard, the class test is not TreeEntry.

What would you say is the correct way to unit test this?

I personally tend to be ridiculed more. Maybe we can say that in the test case I already indicate which are the co-authors of the tested class, because this in some way also relates more to design than to implementation?

Regards, Alex

+4
source share
4 answers

I think your mocking approach looks just fine (and I agree that if TreeEntry as complicated as you say, you shouldn't mix them with these tests (but I hope you check TreeEntry elsewhere)). If you write a lot of such tests, you should consider using some Builder pattern (with smooth syntax if you have the patience to do this) so that you can build a layout, for example. eg:

 BuildANew.TreeEntry().WithPreviousEntryName("testName"); 

or you can create an ITreeEntry interface and write your tree-like code in terms of that interface and create a simple stub implementation to go through your tests, so you don’t have to bother with the installation code layout. Or, for a cleaner approach, create an interface and mock it.

+1
source

I think your best option is to extract the interface from TreeEntry, implement it with the base stub in the test code, and test it.

+1
source

If you want to test

 public String getPreviousName(TreeEntry entry) 

I would scoff at it, since you are only removing this method. And it is good practice for your students to strive quickly.

But if you are interested in testing all access to files and creating your TreeEntry, I would create them.

In my daily work, I first try to write unittests and then construct a function because it helps to create easy-to-use / test interfaces.

http://en.wikipedia.org/wiki/Test-driven_development

0
source

I think the layout is fine.

On the other hand: the JUnit test is not just a test, but also a disk design.

If you find it difficult to write a test case, for example, the constructor takes complex parameters, you can think about your design.

btw, I don’t think the getPreviousName() method is necessary, getPreviousEntry() enough.

0
source

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


All Articles