2016-08-15 2 views
4

메서드가 호출 될 때 어떤 동작을 확인하려고하는 간단한 시나리오가 있습니다 (즉, 특정 매개 변수를 사용하여 특정 메서드가 호출 된 경우,이 시나리오에서는 함수 포인터). 다음은 내 수업은 다음과 같습니다Mockito : 함수 매개 변수를 사용하여 메서드가 호출되었는지 확인

@SpringBootApplication 
public class Application { 

    public static void main(String[] args) { 
     ConfigurableApplicationContext context = SpringApplication.run(Application.class, args); 

     AppBootStrapper bootStrapper = context.getBean(AppBootStrapper.class); 
     bootStrapper.start(); 
    } 
} 

@Component 
public class AppBootStrapper { 
    private NetworkScanner networkScanner; 
    private PacketConsumer packetConsumer; 

    public AppBootStrapper(NetworkScanner networkScanner, PacketConsumer packetConsumer) { 
     this.networkScanner = networkScanner; 
     this.packetConsumer = packetConsumer; 
    } 

    public void start() { 
     networkScanner.addConsumer(packetConsumer::consumePacket); 
     networkScanner.startScan(); 
    } 
} 

@Component 
public class NetworkScanner { 
    private List<Consumer<String>> consumers = new ArrayList<>(); 

    public void startScan(){ 
     Executors.newSingleThreadExecutor().submit(() -> { 
      while(true) { 
       // do some scanning and get/parse packets 
       consumers.forEach(consumer -> consumer.accept("Package Data")); 
      } 
     }); 
    } 

    public void addConsumer(Consumer<String> consumer) { 
     this.consumers.add(consumer); 
    } 
} 

@Component 
public class PacketConsumer { 
    public void consumePacket(String packet) { 
     System.out.println("Packet received: " + packet); 
    } 
} 

@RunWith(JUnit4.class) 
public class AppBootStrapperTest { 

    @Test 
    public void start() throws Exception { 
     NetworkScanner networkScanner = mock(NetworkScanner.class); 
     PacketConsumer packetConsumer = mock(PacketConsumer.class); 
     AppBootStrapper appBootStrapper = new AppBootStrapper(networkScanner, packetConsumer); 

     appBootStrapper.start(); 

     verify(networkScanner).addConsumer(packetConsumer::consumePacket); 
     verify(networkScanner, times(1)).startScan(); 
    } 
} 

내가 실제로 패킷 소비자를 등록하여 올바른 설정을 짓 부트 스트 래퍼를 확인하려면 (이 나중에 등록 된 다른 소비자들 수 있지만, 하나는 필수입니다 수 있음) 다음 startScan했다. 테스트 케이스를 실행할 때 다음과 같은 오류 메시지가 나타납니다.

Argument(s) are different! Wanted: 
networkScanner bean.addConsumer(
    com.spring.starter.AppBootStrapperTest$$Lambda$8/[email protected] 
); 
-> at com.spring.starter.AppBootStrapperTest.start(AppBootStrapperTest.java:24) 
Actual invocation has different arguments: 
networkScanner bean.addConsumer(
    com.spring.starter.AppBootStrapper$$Lambda$7/[email protected] 
); 
-> at com.spring.starter.AppBootStrapper.start(AppBootStrapper.java:12) 

예외적으로 분명히 함수 포인터가 동일하지 않습니다.

올바른 방법으로 접근하고 있습니까? 내가 누락 된 기본적인 것이 있습니까? 나는 놀았고 소비자가 PacketConsumer에 주입되어 다른 제품으로 만들었는지 확인해 보았습니다.하지만 확실히 올바른 방법은 아닙니다.

모든 도움, 전망이 크게 감사하겠습니다.

답변

5

자바에는 "함수 포인터"개념이 없습니다. 당신이 볼 때

networkScanner.addConsumer(new Consumer<String>() { 
    @Override void accept(String packet) { 
    packetConsumer.consumePacket(packet); 
    } 
}); 

이 익명의 내부 클래스는 AppBootStrapper$$Lambda$7를 호출 할 일이 : 자바는 실제로 컴파일 무엇

networkScanner.addConsumer(packetConsumer::consumePacket); 

은 (에 해당)입니다. equals 메서드를 정의하지 않기 때문에 컴파일러가 테스트에서 생성하는 익명의 내부 클래스와 결코 같지 않습니다.이 경우는 AppBootStrapperTest$$Lambda$8이라고합니다. 이는 메서드 본문이 동일하고 동일한 메서드 참조에서 같은 방식으로 작성된다는 사실과는 관계가 없습니다.

테스트에서 명시 적으로 컨슈머를 생성하고 static final Consumer<String> 필드로 저장하면 테스트에서 해당 참조를 전달하고 비교할 수 있습니다. 그 시점에서 참조 평등이 유지되어야한다. 이것은 람다 (lambda) 표현식이나 메쏘드 레퍼런스와 잘 작동 할 것입니다.

더 많은 apt 테스트는 아마도 verify(packetConsumer, atLeastOnce()).consumePacket(...) 일 것입니다. 람다의 내용은 구현 세부 사항이며 구성 요소가 다른 구성 요소와 어떻게 협력하는지에 대해 더욱 관심이 있습니다. 여기에있는 추상화는 addConsumer 레벨이 아닌 레벨이어야합니다.

this SO question에 대한 설명 및 응답을 참조하십시오.

+0

감사합니다. @ Jeff Bowman. 크게 설명했다. 나는 소비자 수준에서 검증한다는 생각을 좋아한다. –

관련 문제