Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/309.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何模拟事件处理程序?_Java_Events_Junit_Mockito - Fatal编程技术网

Java 如何模拟事件处理程序?

Java 如何模拟事件处理程序?,java,events,junit,mockito,Java,Events,Junit,Mockito,我为Stash编写了一个事件处理程序,通过消息总线体系结构发送消息。下面是我的fedmsgEventListener类中的一个示例: @EventListener public void opened(PullRequestOpenedEvent event) { HashMap<String, Object> message = prExtracter(event); String originProjectKey = ((HashMap<String, Ob

我为Stash编写了一个事件处理程序,通过消息总线体系结构发送消息。下面是我的
fedmsgEventListener
类中的一个示例:

@EventListener
public void opened(PullRequestOpenedEvent event)
{
    HashMap<String, Object> message = prExtracter(event);
    String originProjectKey = ((HashMap<String, Object>)message.get("source")).get("project_key").toString();
    String originRepo = ((HashMap<String, Object>)message.get("source")).get("repository").toString();
    String topic = originProjectKey + "." + originRepo + ".pullrequest.opened";
    sendMessage(topic, message);
}
下面是测试调用的类和方法:

import com.atlassian.sal.api.ApplicationProperties;
import com.atlassian.stash.event.pull.*;
import org.mockito.Mock;
import static org.mockito.Mockito.*;

public class MyPluginComponentImpl implements MyPluginComponent
{
    @Mock private PullRequestEvent event;
    @Mock private PullRequestOpenedEvent opened;
    @Mock private FedmsgEventListener fedmsgEventListener;

    public MyPluginComponentImpl(ApplicationProperties applicationProperties)
    {
        this.applicationProperties = applicationProperties;
    }

    public String openPullRequest()
    {
        fedmsgEventListener.opened(opened);
        return fedmsgEventListener.getTopic();
    }

}
现在,该方法抛出一个
NullPointerException
,因为
fedmsgEventListener
PullRequestEvent
都是模拟对象,因此为null


这是对这个场景进行单元测试的最佳方式吗?从较高的层次来看,这就是我想要做的:触发事件,查看主题是否已更改为包含特定字符串的字符串

您使用Mockito是完全错误的。很抱歉首先,
@Mock
如果不使用
initMocks
MockitoJUnitRunner
,就无法工作,但无论如何我不会这样做。模拟为非空;您应该能够在mock上调用方法;在您的例子中,您没有初始化/创建模拟,这就是为什么它们为空

首先,确定要测试的类。这里好像是FedmsgEventListener。然后,使用模拟对象和数据结构与该类的real实例交互,而不是使用具有依赖关系的真实对象等等。注意,我在这里使用

基于模拟的测试建立在:

  • 创建-创建您的模拟,然后声明“当”与该模拟发生交互时,执行某些操作
  • 交互-以您尝试测试的方式与对象交互
  • Verify-使用
    Mockito.Verify
    和JUnit/Hamcrest
    assert
    方法来确保事情按预期的方式进行
  • 您可以这样做:

    import static org.mockito.Mockito.*;
    import static org.hamcrest.MatcherAssert.assertThat;
    import static org.hamcrest.Matchers.containsString;
    
    private HashMap<String, Object> createMessageDetails(String project_key, String repository) {
      HashMap<String, Object> details = new HashMap<>();
      details.put("project_key", project_key);
      details.put("repository", repository);
      return details;
    }
    
    public class FedmsgEventListenerTest {
      @Test
      public void testOpened() {
        // when
        PullRequestOpenedEvent event = mock(PullRequestOpenedEvent.class);
        when(event.someMethodForPrExtracterYouHaventShownMe()).thenReturn(createMessageDetails("myKey", "myRepo"));
    
        // then
        FedmsgEventListener listener = new FedmsgEventListener();
        listener.opened(event);
    
        // verify
        assertThat(event.getTopic(), containsString(".pullrequest.opened"));
        verify(event).someMethodForPrExtracterYouHaventShownMe();
      }
    }
    
    import static org.mockito.mockito.*;
    导入静态org.hamcrest.matcherasert.assertThat;
    导入静态org.hamcrest.Matchers.containssString;
    私有HashMap createMessageDetails(字符串项目密钥,字符串存储库){
    HashMap details=新的HashMap();
    详细信息。放置(“项目密钥”,项目密钥);
    详细信息。放置(“存储库”,存储库);
    退货详情;
    }
    公共类FedmsgEventListenerTest{
    @试验
    公开作废testOpened(){
    //什么时候
    PullRequestOpenedEvent=mock(PullRequestOpenedEvent.class);
    when(event.somemethodforprextracteryyouhaveshownme())。然后返回(createMessageDetails(“myKey”、“myRepo”);
    //然后
    FedmsgEventListener listener=新的FedmsgEventListener();
    listener.opened(事件);
    //核实
    断言(event.getTopic(),包含字符串(“.pullrequest.opened”);
    验证(event).someMethodforPrextracteryYouhaventShowNME();
    }
    }
    
    这段代码可能并不完全是您所需要的,但是您还没有向我展示足够的代码,您正试图为我测试这些代码以使其完全正确。然而,我认为这应该足以让你开始



    另一方面,如果您不能创建具有模拟依赖项的类的真实实例,那么这就是一种代码味道,您的代码应该重构。这就是为什么静态是个坏主意的原因之一,因为如果代码通过静态访问全局状态,那么必须使用静态设置全局状态。使您的类能够处理模拟依赖项,将它们作为参数传递给构造函数,在时使用
    指定模拟行为,然后断言/验证结果。

    @durron597好的,尝试以更好的方式描述它。告诉我是否更好。谢谢你的详尽回答。我的类
    FedmsgEventListener
    似乎在它所监视的事件发生时被实例化。此时,许多与事件相关的参数被提供给类的构造函数。我可能可以模拟这些参数,但我不确定会有什么副作用。不管是哪种方式,谢谢你提供了使用mock的基本说明。@ScottJamesWalter很高兴我能帮上忙。如果发生这种情况,那么听起来您的代码耦合得太紧密,可能会经受住重构。看见
    import static org.mockito.Mockito.*;
    import static org.hamcrest.MatcherAssert.assertThat;
    import static org.hamcrest.Matchers.containsString;
    
    private HashMap<String, Object> createMessageDetails(String project_key, String repository) {
      HashMap<String, Object> details = new HashMap<>();
      details.put("project_key", project_key);
      details.put("repository", repository);
      return details;
    }
    
    public class FedmsgEventListenerTest {
      @Test
      public void testOpened() {
        // when
        PullRequestOpenedEvent event = mock(PullRequestOpenedEvent.class);
        when(event.someMethodForPrExtracterYouHaventShownMe()).thenReturn(createMessageDetails("myKey", "myRepo"));
    
        // then
        FedmsgEventListener listener = new FedmsgEventListener();
        listener.opened(event);
    
        // verify
        assertThat(event.getTopic(), containsString(".pullrequest.opened"));
        verify(event).someMethodForPrExtracterYouHaventShownMe();
      }
    }