如何用 Iterator 覆盖 While 块并用 mockito 和 Junit4 捕获方法?

How to cover the While block with Iterator and catch in a method with mockito and Junit4?

我必须涵盖 Junit4 和 Mockito/PowerMockito While 块和 catch 块。 异常StateException由getHrest方法启动

public class Fstate{
 ….
private Date selectedDate;
private Date dateYes;
private Collection<State> sStateList;
private boolean statePlus;
private String stateVisibility;

@EJB
private Muller mull;
….
public void methodState(){
    final Calendar calendar=new GregorianCalendar();
    this.dateYes=calendar.getTime();
    this.selectedDate = this.dateYes;
    Collection<State> allState=null;
    try{
        allState=this.mull.getHrest(this.p, this.b, this.ba, this.so);
        Iterator<State> iter=allState.iterator();
        while(iter.hasNext()){
            State s=iter.next();
            String s_string=s.getSfielString(); 
            this.sStateList.add(s_string);
        }
     } catch (StateException stateException){
        WebLogger.fatal(stateException.getMessage(), LOGGER_OUT);
    }
    this.statePlus=loadStatePlus(this.dateYes);
    this.stateVisibility=STATE_PLUS;
}
}

下面,在第一种方法中我想涵盖 while 执行,而在第二种方法中我想涵盖 catch。 然而,这并没有产生预期的结果,而 block 和 catch 没有被覆盖!

@Test
public void state_Test(){
    try {
    
        Fstate spyFstate = Mockito.spy(Fstate.class);
        
        State mockState=Mockito.mock(Muller.class);     
        
        Mockito.when(mockState.getHrest(anyString(), anyString(), anyString(), anyString())).thenReturn(createCollectionOfStates());
        Whitebox.setInternalState(spyFstate, "mull",mockState);
        
        spyFstate.methodState();
        Mockito.verify(spyFstate, Mockito.times(1)).methodState();
        
    } catch (StateException e) {
        System.out.println("StateException in state_Test method!");
    }
}
    
@Test
public void stateException_Test(){
    try {
            Fstate spyFstate = Mockito.spy(Fstate.class);
            
            State mockState=Mockito.mock(Muller.class); 
    
            Mockito.when(mockState.getHrest(anyString(), anyString(), anyString(), anyString())).thenThrow(new StateException("StateException Exception"));
            
            Whitebox.setInternalState(spyFstate, "mull",mockState);
            spyFstate.methodState();
            
            Mockito.verify(spyFstate, Mockito.times(1)).methodState();
            
    } catch (DealAnagException e) {
            e.printStackTrace();
    }   
}

我认为你只需要在像这样创建间谍之前实例化你的 Fstate :

Fstate fstate = new Fstate();
Fstate spyFstate = Mockito.spy(fstate);

我在 GhostCat 的帮助下解决了这个问题。

引用:

Note: The real answer might be to further dissect your code. Instead of defining the list in the method to then iterate the list in that method, and update an internal list, why not have a helper method that just takes a list, and returns a list? You can test that completely on its own, without ANY mocking?

And unrelated: flow java naming conventions. s_string is sooo wrong, and says nothing about what the variable is for. Use names that follow conventions and that tell the reader what they are about.

So, long story short: Your production code is overly complicated and if you would follow the "clean code" principles, you would end up with code that would also be much easier to test. That is why people to TDD: When you do tests AFTER you write your production code, you risk ending up with hard-to-test code. And then you need all kinds of complicated "work arounds" in your test code to make up for that. Overly complicated production code leads to overly complicated test code. Which means you just doubled the amount of hard-to-read/understand code.