Mocking a ViewModel for unit testing with Moq? - c#

New to unit testing. I have a WPF client app hooked into a WCF service via basicHttpbinding. Everything works great. I'm using simple constructor Dependency Injection in my viewModel, passing in an IServiceChannel which I then call me service methods on e.g:
IMyserviceChannel = MyService;
public MyViewModel(IMyServiceChannel myService)
{
this.MyService = myService;
}
Private void GetPerson()
{
var selectedPerson = MyService.GetSelectedPerson();
}
I have then added an MS Test project in the client app and I'm trying to use Moq to mock my service:
[TestMethod]
public void GetArticleBody_Test_Valid()
{
// Create channel mock
Mock<IIsesServiceChannel> channelMock = new Mock<IIsesServiceChannel>(MockBehavior.Strict);
// setup the mock to expect the Reverse method to be called
channelMock.Setup(c => c.GetArticleBody(1010000008)).Returns("110,956 bo/d, 1.42 Bcfg/d and 4,900 bc/d. ");
// create string helper and invoke the Reverse method
ArticleDataGridViewModel articleDataGridViewModel = new ArticleDataGridViewModel(channelMock.Object);
string result = channelMock.GetArticleBody(1010000008);
//Assert.AreEqual("cba", result);
//verify that the method was called on the mock
channelMock.Verify(c => c.GetArticleBody(1010000008), Times.Once());
}
The test is failing with a System.NullReferenceException. Object reference not set to an instance of an object. at the method invocation here:
string result = articleDataGridViewModel.IsesService.GetArticleBody(1010000008);
so I'm wandering whether this is the best way to approach or am I better somehow mocking an isolated part of the viewModel which is applicable to the test?

The NullReferenceException is mybe thrown because you use MockBehavior.Strict. The documentation says:
Causes this mock to always throw an exception for invocations that don't have a corresponding setup.
Maybe the constructor of ArticleDataGridViewModel calls other methods of the service which you haven't set up.
Another issue is, that you are calling the mocked method directly. Instead you should call a method of your view model, which calls this method.
[TestMethod]
public void GetArticleBody_Test_Valid()
{
// Create channel mock
Mock<IIsesServiceChannel> channelMock = new Mock<IIsesServiceChannel>();
// setup the mock to expect the Reverse method to be called
channelMock.Setup(c => c.GetArticleBody(1010000008)).Returns("110,956 bo/d, 1.42 Bcfg/d and 4,900 bc/d. ");
// create string helper and invoke the Reverse method
ArticleDataGridViewModel articleDataGridViewModel = new ArticleDataGridViewModel(channelMock.Object);
string result = articleDataGridViewModel.MethodThatCallsService();
//Assert.AreEqual("cba", result);
//verify that the method was called on the mock
channelMock.Verify(c => c.GetArticleBody(1010000008), Times.Once());
}
Besides that I think there is no problem with your approach. Maybe the view model violates the single responsibility principle and does more than it should, but that's hard to tell on the basis of your code example.
EDIT: Here's a full example of how you could test something like this:
public interface IMyService
{
int GetData();
}
public class MyViewModel
{
private readonly IMyService myService;
public MyViewModel(IMyService myService)
{
if (myService == null)
{
throw new ArgumentNullException("myService");
}
this.myService = myService;
}
public string ShowSomething()
{
return "Just a test " + this.myService.GetData();
}
}
class TestClass
{
[TestMethod]
public void TestMethod()
{
var serviceMock = new Mock<IMyService>();
var objectUnderTest = new MyViewModel(serviceMock.Object);
serviceMock.Setup(x => x.GetData()).Returns(42);
var result = objectUnderTest.ShowSomething();
Assert.AreEqual("Just a test 42", result);
serviceMock.Verify(c => c.GetData(), Times.Once());
}
}

Without access to your viewmodel, there's only so much help that we can provide you.
However, this code:
Mock<IIsesServiceChannel> channelMock = new Mock<IIsesServiceChannel>(MockBehavior.Strict);
...
ArticleDataGridViewModel articleDataGridViewModel = new ArticleDataGridViewModel(channelMock.Object);
...
string result = articleDataGridViewModel.IsesService.GetArticleBody(1010000008);
Does not set up your IsesService. If it is not set up in your constructor, that means the IsesService is a null reference. You can't call a method on a null object.

Consider mocking out at a higher level of abstraction then the tight coupling you have with the tool your using.
Perhaps your view-model should rely on services and not a detail of the tool that your using (i.e. IIsesServiceChannel).
Here's an example:
Construct testable business layer logic

Related

Unti Test: Mock a method result

public void Pay()
{
// some insert db code
// ...
// Call Bank api
BankApi api = new BankApi();
int result = api.pay();
if(result == 1)
{
//...
}
else
{
//...
}
}
I dont want to call api in unit test. How to mock the pay method without modify inner code (such as the line new BankApi() code)?
Its possible to mock your BankApi class without changing any of your legacy code, you just need a unit testing framework that allows you to mock concrete classes.
for example a test for your method with Typemock :
[TestMethod]
public void ExampleTest()
{
//fakes the next BankApi instace
var handler = Isolate.Fake.NextInstance<BankApi>();
//change the pay method behavior
Isolate.WhenCalled(() => handler.pay()).WillReturn(1);
new ClassUnderTest().Pay();
}
First, as stated, you should create an Interface.
public interface IBankApi
{
int pay();
}
Then, what you can do is mock this interface like this (I'm using Moq "Mock you" here, you will need to add the NuGet package "Moq" as reference to your application, and you could use other mocking libraries of course)
apiMock = new Mock<IBankApi>();
just after that you will tell what this call should return (that would be actual mocking)
apiMock.Setup(x => x.pay()).Returns(1); //
Then, this api "pseudo object", can be used by using apiMock.Object
Now , this information I just gave you doesn't directly solve your problem.
As stated in the comments, you need a better uncoupling of your code.
You need, for example, some kind of "dependency injection" to allow for such a uncoupling.
Here is a simple example of how it can be done :
public class ClassThatUsesYourBankApi
{
private readonly IBankApi _api;
// the constructor will be given a reference to the interface
public ClassThatUsesYourBankApi (IBankApi api)
{
// here you could check for null parameter and throw exception as needed
this._api = api;
}
// this method can now be tested with the mock interface
public void MethodThatUseTheApi()
{
int result = this._api.pay();
if (result == 1)
{
// some things that happens
}
else
{
// some other thing
}
}
}
How to unit test that method :
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
[TestClass]
public class TestMyMethod
{
[TestMethod]
public void MyMethod_WithBankApiReturns1_ShouldHaveThingsThatHappens()
{
// Arrange
var apiMock = new Mock<IBankApi>();
apiMock.Setup(api => api.pay())
.Returns(1);
var myObject = new ClassThatUsesYourBankApi(apiMock.Object);
// Act
int result = myObject.MethodThatUseTheApi();
// Assert
// Here you test that the things that should have happened when the api returns 1 actually have happened.
}
}
The key thing to understand here, is that you must not instantiate the api you need to mock in the method you want to test
In other words, "uncoupling" your method with your api is done by programming to an interface, and code such as you don't have
var api = new BankApi()
directly in the method you want to unit test.
I showed a way to do that, and there are other.

Unit Testing a controller that uses windows authentication

-------Please see updates below as I now have this set up for dependency injection and the use of the MOQ mocking framework. I'd still like to split up my repository so it doesn't directly depend on pulling the windowsUser within the same function.
I have a Web API in an intranet site that populates a dropdown. The query behind the dropdown takes the windows username as a parameter to return the list.
I realize I don't have all of this set up correctly because I'm not able to unit test it. I need to know how this "should" be set up to allow unit testing and then what the unit tests should look like.
Additional info: this is an ASP.NET MVC 5 application.
INTERFACE
public interface ITestRepository
{
HttpResponseMessage DropDownList();
}
REPOSITORY
public class ExampleRepository : IExampleRepository
{
//Accessing the data through Entity Framework
private MyDatabaseEntities db = new MyDatabaseEntities();
public HttpResponseMessage DropDownList()
{
//Get the current windows user
string windowsUser = HttpContext.Current.User.Identity.Name;
//Pass the parameter to a procedure running a select query
var sourceQuery = (from p in db.spDropDownList(windowsUser)
select p).ToList();
string result = JsonConvert.SerializeObject(sourceQuery);
var response = new HttpResponseMessage();
response.Content = new StringContent(result, System.Text.Encoding.Unicode, "application/json");
return response;
}
}
CONTROLLER
public class ExampleController : ApiController
{
private IExampleRepository _exampleRepository;
public ExampleController()
{
_exampleRepository = new ExampleRepository();
}
[HttpGet]
public HttpResponseMessage DropDownList()
{
try
{
return _exampleRepository.DropDownList();
}
catch
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));
}
}
}
UPDATE 1
I have updated my Controller based on BartoszKP's suggestion to show dependency injection.
UPDATED CONTROLLER
public class ExampleController : ApiController
{
private IExampleRepository _exampleRepository;
//Dependency Injection
public ExampleController(IExampleRepository exampleRepository)
{
_exampleRepository = exampleRepository;
}
[HttpGet]
public HttpResponseMessage DropDownList()
{
try
{
return _exampleRepository.DropDownList();
}
catch
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));
}
}
}
UPDATE 2
I have decided to use MOQ as a mocking framework for unit testing. I'm able to test something simple, like the following. This would test a simple method that doesn't take any parameters and doesn't include the windowsUser part.
[TestMethod]
public void ExampleOfAnotherTest()
{
//Arrange
var mockRepository = new Mock<IExampleRepository>();
mockRepository
.Setup(x => x.DropDownList())
.Returns(new HttpResponseMessage(HttpStatusCode.OK));
ExampleController controller = new ExampleController(mockRepository.Object);
controller.Request = new HttpRequestMessage();
controller.Configuration = new HttpConfiguration();
//Act
var response = controller.DropDownList();
//Assert
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}
I need help testing the DropDownList method (one that does include code to get the windowsUser). I need advice on how to break this method apart. I know both parts shouldn't been in the same method. I don't know how to arrange splitting out the windowsUser variable. I realize this really should be brought in as a parameter, but I can't figure out how.
You usually do not unit-test repositories (integration tests verify if they really persist the data in the database correctly) - see for example this article on MSDN:
Typically, it is difficult to unit test the repositories themselves, so it is often better to write integration tests for them.
So, let's focus on testing only the controller.
Change the controller to take IExampleRepository in its constructor as a parameter:
private IExampleRepository _exampleRepository;
public ExampleController(IExampleRepository exampleRepository)
{
_exampleRepository = exampleRepository;
}
Then, in your unit tests, use one of mocking frameworks (such as RhinoMock for example) to create a stub for the sole purpose of testing the controller.
[TestFixture]
public class ExampleTestFixture
{
private IExampleRepository CreateRepositoryStub(fake data)
{
var exampleRepositoryStub = ...; // create the stub with a mocking framework
// make the stub return given fake data
return exampleRepositoryStub;
}
[Test]
public void GivenX_WhenDropDownListIsRequested_ReturnsY()
{
// Arrange
var exampleRepositoryStub = CreateRepositoryStub(X);
var exampleController = new ExampleController(exampleRepositoryStub);
// Act
var result = exampleController.DropDownList();
// Assert
Assert.That(result, Is.Equal(Y));
}
}
This is just a quick&dirty example - CreateRepositoryStub method should be of course extracted to some test utility class. Perhaps it should return a fluent interface to make the test's Arrange section more readable on what is given. Something more like:
// Arrange
var exampleController
= GivenAController()
.WithFakeData(X);
(with better names that reflect your business logic of course).
In case of ASP.NET MVC, the framework needs to know how to construct the controller. Fortunately, ASP.NET supports the Dependency Injection paradigm and a parameterless constructor is not required when using MVC unity.
Also, note the comment by Richard Szalay:
You shouldn't use HttpContext.Current in WebApi - you can use base.User which comes from HttpRequestBase.User and is mockable. If you really want to continue using HttpContext.Current, take a look at Mock HttpContext.Current in Test Init Method
One trick that I find very useful when trying to make old code testable when said code is accessing some global static or other messy stuff that I can't easily just parameterize is to wrap access to the resource in a virtual method call. Then you can subclass your system under test and use that in the unit test instead.
Example, using a hard dependency in the System.Random class
public class Untestable
{
public int CalculateSomethingRandom()
{
return new Random().Next() + new Random().Next();
}
}
Now we replace var rng = new Random();
public class Untestable
{
public int CalculateSomethingRandom()
{
return GetRandomNumber() + GetRandomNumber();
}
protected virtual int GetRandomNumber()
{
return new Random().Next();
}
}
Now we can create a testable version of the class:
public class Testable : Untestable
{
protected override int GetRandomNumber()
{
// You can return whatever you want for your test here,
// it depends on what type of behaviour you are faking.
// You can easily inject values here via a constructor or
// some public field in the subclass. You can also add
// counters for times method was called, save the args etc.
return 4;
}
}
The drawback with this method is that you can't use (most) isolation frameworks to implement protected methods (easily), and for good reason, since protected methods are sort of internal and shouldn't be all that important to your unit tests. It's still a really handy way of getting things covered with tests so you can refactor them, instead of having to spend 10 hours without tests, trying to do major architectual changes to your code before you get to "safety".
Just another tool to keep in mind, I find it comes in handy from time to time!
EDIT: More concretely, in your case you might want to create a protected virtual string GetLoggedInUserName(). This will technically speaking keep the actual call to HttpContext.Current.User.Identity.Name untested, but you will have isolated it to the simplest smallest possible method, so you can test that the code is calling the correct method the right amount of times with the correct args, and then you simply have to know that HttpContext.Current.User.Identity.Name contains what you want. This can later be refactored into some sort of user manager or logged in user provider, you'll see what suits best as you go along.

Unit Testing Method with Moq where Collection = serivce.GetCollection()?

New to unit testing & Moq. I have a WPF client app which hooks into a WCF service via HttpBinding. I have a test class in MSTest and I'm mocking my service with Moq like so:
[TestClass]
public class ArticleDataGridTests
{
//Mock channel for WCF service. Moq mocking framework.
Mock<IIsesServiceChannel> channelMock = new Mock<IIsesServiceChannel>();
[TestMethod]
public void LoadArticleTitlesListTestValid()
{
channelMock.Setup(c => c.GetArticleTitles());
ArticleDataGridViewModel articleDataGridViewModel = new ArticleDataGridViewModel(channelMock.Object);
articleDataGridViewModel.LoadArticleTitlesList();
channelMock.Verify(c => c.GetArticleTitles(), Times.Once());
}
}
}
Here is the method LoadArticleTitles list that's being invoked in the ViewModel. ArticlesTitleList is a List<string>:
public void LoadArticleTitlesList()
{
ArticleTitlesList = new List<string>(IsesService.GetArticleTitles());
}
Obviously this test fails. I get a null exception on the 'collection'. How do I mock this list of strings for my test or should I not be writing void method stubs with WCF service method calls which return lists nested inside them in the first place? Thanks
You need to return data after setup:
var listOfStrings = new List<string>{{"test1"}};
channelMock.Setup(c => c.GetArticleTitles()).Returns(listOfStrings);
Had to pass in an array of string rather than a List<string> as WCF looks like a method that returns a .ToList() is stubbed out as returning an []string in the boiler plate code. Therefore passing in a list of string gives an overloaded method invalid argument exception. Ended up with this:
var ArticleTitlesList = new string[] { "LoadArticleTitlesListTestValid" };
channelMock.Setup(c => c.GetArticleTitles()).Returns(ArticleTitlesList);

Unit Testing Interfaces with Moq

I'm new to Moq and unit testing. I have been doing a unit test and this is the following code:
private Mock<IServiceAdapter> repository;
[TestInitialize]
public void Initialize()
{
repository= new Mock<IServiceAdapter>();
}
[TestMethod()]
public void SaveTest()
{
//Setup
string Name = "Name1";
string Type = "1";
string parentID = null;
repository.Setup(x => x.Save(Name , Type, parentID)).Returns("Success").Verifiable();
//Do
var result = repository.Object.Save(Name , Type, parentID);
//Assert
repository.Verify();
}
My problem is that the test will always return the string that I put in the Returns parameter, in other words, it will always return "success" or whatever I write in its place. I guess thats not right because thats not the real behavior of the service. Anyone knows how I can mirror the real behavior of the "Save" service I'm trying to test? So lets say, if the return string is different from the service method,then the test should fail.
Edited
The ServiceAdapter interface its just a wrapper for a Web Service which I call like a REST Service. It's a Web Forms Project.
I'm doing something like in this post
How to mock a web service
Should I create something like a FakeController with Dependency Injection to make it work?
You are testing mock here, which gives you nothing (because this mock is not used in your real application). In unit-testing you should create and test your real objects, which exist in your real application (i.e. interface implementations). Mocks used for mocking dependencies of objects under test.
So, mock of service adapter will be useful for tests of object, which uses that adapter, e.g. some controller tests:
private FooController _controller; // object under test, real object
private Mock<IServiceAdapter> _serviceAdapter; // dependency of controller
[TestInitialize]
public void Initialize()
{
_serviceAdapter = new Mock<IServiceAdapter>();
_controller = new FooController(_serviceAdapter.Object);
}
[TestMethod()]
public void SaveTest()
{
// Arrange
string name = "Name1";
string type = "1";
string parentID = null;
_serviceAdapter.Setup(x => x.Save(name , type, parentID))
.Returns("Success").Verifiable();
// Act on your object under test!
// controller will call dependency
var result = _controller.Bar(name , type, parentID);
// Assert
Assert.True(result); // verify result is correct
_serviceAdapter.Verify(); // verify dependency was called
}

How to mock web service call with Moq?

The using below hits an external resource that I do not want to actually hit. I want to test someResult and the code that uses it, but every time I run my unit test, this code still tries to hit the real web service. How do I use moq to fake the real call to the web service, but not mock the rest of the code within the using?
public IMyInterface.SomeMethod()
{
// hits a web service
using ( mySoapClient client = new mySoapClient() )
{
var someResult = client.DoSomething();
...
...
}
}
[TestMethod()]
public void SomeMethodTest()
{
IMyInterface target = new MyInterface();
target.SomeMethod();
// Assert....
}
You need to decouple the web service implementation from the consumer
public class ClassIWantToTest
{
public ClassIWantToTest(IServiceIWantToCall service) {}
public void SomeMethod()
{
var results = service.DoSomething();
//Rest of the logic here
}
}
Now you can use Moq to mock the IServiceIWantToCall in order to test the logic of SomeMethod
To add to pickles' answer, I created an interface for my current service calls named IService. I then created a ServiceMock class that inherits the interface and added a global variable named _service. In the constructor I instantiate the mock service and set up all the methods of the interface as such:
public class ServiceMock : IService
{
Mock<IService> _serviceMock;
public ServiceMock()
{
_serviceMock = new Mock<IService>();
_serviceMock.Setup(x => x.GetString()).Returns("Default String");
SomeClass someClass = new SomeClass();
someClass.Property1= "Default";
someClass.Property2= Guid.NewGuid().ToString();
_serviceMock.Setup(x => x.GetSomeClass()).Returns(someClass);
}
public string GetString()
{
return _serviceMock.Object.GetString();
}
public License GetSomeClass()
{
return _serviceMock.Object.GetSomeClass();
}
}
You then inject this class into your code instead of the actual web service. It will return the values you set it up to return. You can now test without depending on your web service.
You first have to be able to inject the web service. Creating a new one inside SomeMethod() "tightly couples" the method to the production code; you can't dynamically tell it to create something other than a mySoapClient.
Since you want to create and destroy them, might I suggest that the code you want to test accept a Func<IMySoapClient> as a method parameter or as a constructor parameter. It would look something like this:
public IMyInterface.SomeMethod(Func<IMySoapClient> clientFactory)
{
// hits a web service
using ( mySoapClient client = clientFactory() )
{
var someResult = client.DoSomething();
...
...
}
}
... or:
public class MyClass:IMyInterface
{
private Func<IMySoapClient> MySoapClientFactoryMethod;
public MyClass(Func<IMySoapClient> clientFactoryMethod)
{
MySoapClientFactoryMethod = clientFactoryMethod;
}
...
public IMyInterface.SomeMethod()
{
// hits a web service
using ( mySoapClient client = MySoapClientFactoryMethod() )
{
var someResult = client.DoSomething();
...
...
}
}
}
Now, when you create the object you are trying to test, you define a function that generates the appropriate Moq mock of the Soap service, which has the behavior you would expect from the real client without the side effects (including being able to tell that the code Dispose()d of the client), and pass that function into the class or method that you're testing. In production, you could simply define the function as ()=>new mySoapClient(), or you could set up an IoC framework and register mySoapClient as an IMySoapClient, then also register MyClass; most IoC frameworks are smart enough to see the delegate as a parameter and generate the method that injects the registered dependency.

Categories