简体   繁体   中英

how to do unit test in a method that contains a local Set<String> variable?use powerMock or Mockito

I have a class like below:

public class Connection{

    public boolean isDBConnectionRelativeException(String key) {
        Set<String> keySet = new HashSet<>();
        keySet.add("key1");
        keySet.add("key2");
        keySet.add("key3");
        if (keySet.contains(key)) {
            return true;
        }
        return false;
    }
}

and I don't know how to do unit test with it

I find similar situation in [ How to mock the return value of a Map?

but I think it is not a same problem. I try to do it with PowerMockito as below, but it doesn't work

@RunWith(PowerMockRunner.class)
@PrepareForTest({HashSet.class})
public class ConnectionExceptionAspectTest {
    private Connection connectionExceptionAspect;
    @Before
    public void init(){
        Mockito.validateMockitoUsage();
        connectionExceptionAspect = new Connection();
    }
    @Test
    public void isDBConnectionRelativeExceptionMock() {

        Set<String> stringSet = new HashSet<>();
        Set<String> clazzSet = spy(stringSet);
        try {
            PowerMockito.whenNew(HashSet.class).withNoArguments().thenReturn((HashSet) clazzSet);
            PowerMockito.when(clazzSet.contains("key")).thenReturn(true);

        }catch (Exception e){
            e.printStackTrace();
        }
       assertTrue(connectionExceptionAspect.isDBConnectionRelativeException("key"));

    }
}

please help me make a unit test with it!thanks!

**//after edit one time **
In the real situation, Set keySet is constructed with

Set<String> keySet = new HashSet<>();

, keySet.add(element) can't run in test case, it is more complicated. so I just want to mock it to get my result like

PowerMockito.when(keySet.contains("key")).thenReturn(true);

I know PowerMockito can mock a local new variable instance, but I don't know how to do with a local new map instance. I can't find any about this. I am very grateful to all those who are concerned about this issue. My English is terrible to explain my question.

//after edit second time
I know how to mock a POJO local new variable instance, but I don't know how to mock a Set< String >, Map< String,String > etc local new variable instance. I think they are quite different. that's the problem: how to mock a local Set< String >, Map< String,String > etc instance.

There is no need to mock local variable for the above method.

@Test
    public void isDBConnectionRelativeExceptionMock() {
       assertTrue(connection.isDBConnectionRelativeException("key1"));
       assertTrue(connection.isDBConnectionRelativeException("key4"));
    }

I'm not sure if that will be answer to your question, but try this code:

@Test
public void isDBConnectionRelativeExceptionMock() {
    Set<String> stringSet = mock(HashSet.class);
    when(stringSet.add(anyString())).then(invocation -> false);
    when(stringSet.contains("java.net.ConnectException")).thenReturn(true);
    try {
        PowerMockito.whenNew(HashSet.class).withNoArguments().thenReturn((HashSet) stringSet);
    }catch (Exception e){
        e.printStackTrace();
    }
    assertTrue(dataRepository.isDBConnectionRelativeException("java.net.ConnectException"));
}

You will need to change your PrepareForTest annotation to @PrepareForTest({Connection.class}) .

From the PowerMockito docu :

This annotation tells PowerMock to prepare certain classes for testing. Classes needed to be defined using this annotation are typically those that needs to be byte-code manipulated


As others pointend out doing things like that isn't the best way do solve this problem. If you want a more "usefull" answer provide a real example of what your code is actually doing.

Ideally the HashSet should be contained or delivered by another dependency that could be mocked.


I know how to mock a POJO local new variable instance, but I don't know how to mock a Set, Map etc local new variable instance. I think they are quite different. that's the problem: how to mock a local Set< String>, Map etc instance.

There is no mentionable difference. You mock the class and define the behaviour. But the usual suggestion is not to mock objects you can easily create.

Why don't you just mock Connection and have isDBConnectionRelativeExceptionMock always return true?

Alternatively, you can have a new method buildKeySet that returns your Set and then have a spy to keep some of the functionality in place and some mocked. So you wouldn't need to mock a variable but a method - straight forward

As a rule of thumb, whenever you have difficulty unit testing some code it is a sign the code you are testing is not well enough designed. One big benefit of unit testing is that it points out the need to refactor. To be honest, spies are also a bit of a code smell but not undestanding what your code does or even what you are trying to test I can't suggest better.

Also, PowerMock is kind of a cannon you shouldn't use to shoot small flies, think twice before using it: do you really need to? is the code you're testing in need of some refactoring?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM