简体   繁体   中英

Unit Testing Methods that make WCF Service Call?

First attempt at any real unit testing. I have a WPF client application which receives data from methods in a WCF service. These method calls are made directly from my view models in the client app:

   public string LoadArticle()
    {
       MyServiceClient msc = new MyServiceClient();
       return Article = msc.GetArticle(_UserName);
    }

I then have a test project where I new up a viewmodel then call my method:

    [TestMethod]
    public void LoadArticleTestValid()
    {
        var articleViewModel = new ArticleViewModel("Thomas");

        string userName = "Thomas";
        string expected = "Article 1";

        var actual = articleViewModel.LoadArticle(userName); 

        etc.           
    }

Obviously this test will fail because the client application cannot reach the service to invoke LoadArticle . How is this situation tackled? Do I use Dependency Injection and pass a IMyService interface of some kind into the constructor instead of creating MyServiceClient in the ViewModel or do I mock the service somehow?

This is the problem:

MyServiceClient msc = new MyServiceClient();

This creates a tight coupling between ArticleViewModel and MyServiceClient . In order to unit test just ArticleViewModel this dependency would need to be mocked. If there's an IMyServiceClient then you'd supply that to the class:

public ArticleViewModel
{
    private IMyServiceClient ServiceClient { get; set; }

    public ArticleViewModel(IMyServiceClient serviceClient)
    {
        this.ServiceClient = serviceClient;
    }

    // etc.
}

Then code within that class wouldn't create a new service client, it would just use the one that's in that property.

Then in the unit test you'd create a mock of IMyServiceClient , define expected behaviors on that mock, and supply it to the object being tested. How you do that depends on the mocking library. A quick example in Rhino Mocks might look like this:

// arrange
var serviceClient = MockRepository.GenerateMock<IMyServiceClient>();
serviceClient.Stub(c => c.GetArticle(Arg<string>.Is.Anything)).Return("Article 1");

var model = new ArticleViewModel(serviceClient);

// act
var result = model.LoadArticle("Thomas");

// assert
Assert.AreEqual("Article 1", result);

The idea here is that the unit test is only testing the LoadArticle method, not the dependencies invoked by that method. Those dependencies are supplied with expected behaviors and the result is examined based on those expected behaviors.

Note: There's nothing stopping the unit test from supplying the actual implementation of MyServiceClient as well, instead of a mock. The unit test project just needs the configuration for that service to work. (Unit test projects are application hosts, they can have App.config files.) This would be an integration test rather than a unit test, but the same assertions of the results can be made.

Yes, I think you are right I would suggest a constructor parameter of IMyService, which you can use to inject a mock into the object for testing.

Further! I would suggest not using the autogenerated service client. if you copy and paste the code out into your own class you can make it implement IMyService and effectivly hide the fact that it uses WCF, goes direct to the DB or is a mocked object from the real code.

this will allow you to inject your Mock into the WPF for UI testing

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