2017-11-21 3 views
1

Ich habe eine einfache Steuerung, die Einheit getestet werden muss nicht Integration getestet. Ich brauche nur einen Weg, um zu verhöhnen, so dass ich überprüfen kann, ob die receive-Methode aufgerufen wird. Wir haben bereits einen Test gegen Receive(), also brauchen wir nicht zu überprüfen, was in dieser Methode passiert.Mock eine Steuerung für Komponententest ohne Service-Referenz C#

Mein Code sieht aus wie

public class MessageController : Controller 
{  
    private readonly ConnectionDetail connectionDetail; 

    private readonly QueueDetail queueDetail; 

    public MessageController(IOptions<ConnectionDetail> connectionDetail, IOptions<QueueDetail> queueDetail) 
    { 
     this.connectionDetail = connectionDetail.Value; 
     this.queueDetail = queueDetail.Value; 
    } 

    [HttpGet()] 
    public IActionResult Get() 
    { 
     try 
     { 
      var channel = CreateConnectionAndChannel(queueDetail); 
      var message = channel.Receive();    
      var hbaseKey = new HbaseKey { Key = new Guid(message) }; 
      return Ok(hbaseKey); 
     } 
     catch 
     { 
      return StatusCode(500, "Exception occured while processing. Try again."); 
     } 
    } 

    private IChannel CreateConnectionAndChannel(QueueDetail queueDetail) 
    { 
     var factory = new Factory(); 
     var adapter = factory.Connect(MessagingType.MQ, connectionDetail);   
     return adapter.BindQueue(queueDetail); 
    } 
} 
+2

Sie haben eine 'neue Fabrik()' dort aussehen könnte. Im Allgemeinen ist jeder Code, der 'new' enthält, nicht testbar. Sie müssen eine "IFactoryFactory" injizieren, fürchte ich. – CodeCaster

+0

Sie sollten die 'CreateConnectionAndChannel'-Funktionalität als Teil einer anderen Klasse haben und diese sollte als Abhängigkeit zum Controller injiziert werden. Und Unit-Tests sollten dies zusammen mit anderen Mocks zu Unit-Test-Controller verwenden –

+0

@CodeCaster - Das ist, was ich dachte :( – Developer

Antwort

1

Umgestalten die CreateConnectionAndChannel Funktion hinaus in seinen eigenen Dienst

public interface IChannelProvider { 
    IChannel CreateConnectionAndChannel(); 
} 

und haben Controller explizit abhängig von diesem Service

public class MessageController : Controller { 
    private readonly IChannelProvider channelProvider; 

    public MessageController(IChannelProvider channelProvider) { 
     this.channelProvider = channelProvider; 
    } 

    [HttpGet()] 
    public IActionResult Get() { 
     try { 
      var channel = channelProvider.CreateConnectionAndChannel(); 
      var message = channel.Receive();    
      var hbaseKey = new HbaseKey { Key = new Guid(message) }; 
      return Ok(hbaseKey); 
     } catch { 
      return StatusCode(500, "Exception occured while processing. Try again."); 
     } 
    }  
} 

Jetzt muss nur der IChannelProvider verspottet werden, um den Controller isoliert zu testen.

Ich brauche nur eine Möglichkeit zu mock, so dass ich überprüfen kann, ob die Empfangsmethode aufgerufen wird.

public void Verify_Received_Called() { 
    //Arrange 
    var channel = new Mock<IChannel>(); 
    channel 
     .Setup(_ => _.Receive()) 
     .Returns("My mock value here"); 

    var mockProvider = new Mock<IChannelProvider>(); 
    mockProvider.Setup(_ => _.CreateConnectionAndChannel()) 
     .Returns(channel.Object); 

    var controller = new MessageController(mockProvider.Object); 

    //Act 
    var result = controller.Get(); 

    //Assert  
    channel.Verify(_ => _.Receive(), Times.AtLeastOnce); 
} 

Die Provider-Implementierung wie ...

public class ChannelProvider : IChannelProvider {  
    private readonly ConnectionDetail connectionDetail; 
    private readonly QueueDetail queueDetail; 

    public ChannelProvider(IOptions<ConnectionDetail> connectionDetail, IOptions<QueueDetail> queueDetail) { 
     this.connectionDetail = connectionDetail.Value; 
     this.queueDetail = queueDetail.Value; 
    }  

    public IChannel CreateConnectionAndChannel() { 
     var factory = new Factory(); 
     var adapter = factory.Connect(MessagingType.MQ, connectionDetail);   
     return adapter.BindQueue(queueDetail); 
    } 
} 
1

Um dies zu tun, müssen Sie Ihre CreateConnectionAndChannel Methode in eine separate Abhängigkeit bewegen, zum Beispiel, die Channel IChannelFactory Schnittstelle implementiert.

public interface IChannelFactory { 
    IChannel CreateConnectionAndChannel(QueueDetail queueDetail); 
} 

public class ChannelFactory : IChannelFactory { 
    public IChannel CreateConnectionAndChannel(QueueDetail queueDetail) 
    { 
     var factory = new Factory(); 
     var adapter = factory.Connect(MessagingType.MQ, connectionDetail);   
     return adapter.BindQueue(queueDetail); 
    } 
} 

public class MessageController : Controller 
{  
    private readonly ConnectionDetail connectionDetail; 
    private readonly QueueDetail queueDetail; 
    private readonly IChannelFactory channelFactory; 

    public MessageController(IOptions<ConnectionDetail> connectionDetail, IOptions<QueueDetail> queueDetail, IChannelFactory channelFactory) 
    { 
     this.connectionDetail = connectionDetail.Value; 
     this.queueDetail = queueDetail.Value; 
     this.channelFactory = channelFactory; 
    } 

    [HttpGet()] 
    public IActionResult Get() 
    { 
     try 
     { 
      var channel = channelFactory.CreateConnectionAndChannel(queueDetail); 
      var message = channel.Receive();    
      var hbaseKey = new HbaseKey { Key = new Guid(message) }; 
      return Ok(hbaseKey); 
     } 
     catch 
     { 
      return StatusCode(500, "Exception occured while processing. Try again."); 
     } 
    } 
} 

Danach können Sie Ihren Controller in Test (mit Moq zum Beispiel) verspotten:

[TestFixture] 
public class TestMessageController 
{ 
    [Test] 
    public void TestGet() 
    { 
     var channelMock = new Mock<IChannel>(MockBehavior.Strict); 
     channelMock 
      .Setup(c => c.Receive()) 
      .Returns(null); 

     var channelFactoryMock = new Mock<IChannelFactory>(MockBehavior.Strict); 
     channelFactory 
      .Setup(cf => cf.CreateConnectionAndChannel(It.IsAny<IOptions<QueueDetail>>())) 
      .Returns(); 

     var controller = new MessageController(null, null, channelFactoryMock.Object); 
     controller.Get(); 
    } 
} 
Verwandte Themen