-------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.
Related
I am working in an ASP.net MVC 5 application. I would like to Unit Test my controller action which looks like this
public ActionResult Search()
{
var vm = SetupSearchViewModel();
return View(vm);
}
All the hard work is done by the SetupSearchViewModel() method, which itself is an orchestrator calling many different other methods, one of which is this
private string ExtractJsonFile(string filename)
{
var filePath = HttpContext.Server.MapPath(filename);
var json = System.IO.File.ReadAllText(filePath);
return json;
}
I plan on doing many Unit Tests on this particular action, but I'm starting with a very simple Unit Test which checks that the correct type of ActionResult is returned
[Test]
public void Search_Get_ReturnsViewResult()
{
// arrange
var performanceController = PerformanceControllerInstance;
// act
var result = performanceController.Search();
//assert
Assert.IsNotNull(result as ViewResult);
}
The test is failing because of the ExtractJsonFile method. It uses HttpContext and that is null. I am using Rhino Mocks to do the mocking of the various classes.
What would be the best way to Unit Test this? Darin in this thread suggest we avoid HttpContext.Current if we want our code Unit Tested.
By the way I tried mocking the HttpContext and made it not null, but then the Server is null, I can go ahead and mock that too I suppose (I don't know how yet), but is there no better way? I've no problem doing major refactoring if needed.
HttpContext.Server.MapPath would require an underlying virtual directory provider which would not exist during the unit test. Abstract the path mapping behind a service that you can mock to make the code testable.
public interface IPathProvider {
string MapPath(string path);
}
In the implementation of the concrete service you can make your call to map the path and retrieve the file.
public class ServerPathProvider: IPathProvider {
public string MapPath(string path) {
return HttpContext.Current.Server.MapPath(path);
}
}
you would inject the abstraction into your controller or where needed and used
public MyController : Controller {
public MyController(IPathProvider pathProvider) {
this.pathProvider = pathProvider;
}
//...other code removed for brevity
private string ExtractJsonFile(string filename) {
var filePath = pathProvider.MapPath(filename);
var json = System.IO.File.ReadAllText(filePath);
return json;
}
}
Using your mocking framework of choice you can then mock the provider
[Test]
public void Search_Get_ReturnsViewResult() {
// arrange
IPathProvider mockedPathProvider = //...insert your mock/fake/stub here
var performanceController = PerformanceControllerInstance(mockedPathProvider);
// act
var result = performanceController.Search();
//assert
Assert.IsNotNull(result as ViewResult);
}
and not be coupled to HttpContext
You could even go further and refactor the entire ExtractJsonFile(string filename) into its own service to get around being tied to disk as well.
public interface IJsonProvider {
string ExtractJsonFile(string filename);
}
This service is now flexible enough to get the file from other sources like web service if needed.
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.
I'm new to unit testing and I'm really stuck atm so I could really use some help.
Some application info
I have a WPF application in MVVM. It gets data from a database (classes generated via .edmx).
All linq queries are handled by methods in the Database class.
In CustomerListViewModel, it makes a list of all Customers to be shown in the CustomerListView.
My problem
I am new to Unit Testing. I've read about it and tried to make it work. But as I understand, it should/can be done without touching the DB. I tried to find as much info as I could, but it wouldn't work with what I have. And now I'm basically stuck.
My question
How do I unit test this piece of code? How can I know if I've successfully queried the database (with or without touching the DB in the unit test)?
(If I understand it for this piece, I can figure the rest of the classes and methods out on my own)
The code
CustomerListViewModel:
public CustomerListViewModel()
{
MyObservableCollection<Customer> listCustomers = new MyObservableCollection<Customer>();
ListCustomers = App.Database.GetCustomerList();
}
private void GetListCustomers()
{
ListCustomers = App.Database.GetCustomerList();
if (App.Database.hasError)
App.Messenger.NotifyColleagues("SetStatus", App.Database.errorMessage);
}
Database:
public MyObservableCollection<Customer> GetCustomerList()
{
hasError = false;
MyObservableCollection<Customer> customerList = new MyObservableCollection<Customer>();
try
{
QRM_Entities dc = new QRM_Entities();
var query =
from customers in dc.Customer
select customers;
foreach (Customer cust in query)
{
customerList.Add(cust);
}
}
catch (Exception ex)
{
errorMessage = "GetCustomerList() error, " + ex.Message;
hasError = true;
}
return customerList;
}
The way that you have the ViewModel currently setup will make it almost impossible to unit test.
The issue is on this line:
ListCustomers = App.Database.GetCustomerList();
I presume that App is a static and Database is the class that you are using as your Data Access Layer. So everytime that you call the constructor of your CustomerListViewModel you will call the actual Static implementation of App which you would have to setup before creating the View Model, meaning that you would always be testing with the actual Database, which is obviously what you are attempting to bypass.
In comes my favorite software principle the Dependency Inversion Principle, the premise of this is that decouple modules so that your high level module depends on an abstraction of a lower level module. And that details should depend on that abstraction. Effectively you should develop to an interface and provide this interface to dependents.
Taking your example I would extract interfaces for your database interaction and provide these to your View Model, but I'll go a step further and provide this to a model which will be provided to your view model.
IDatabase:
public interface IDatabase
{
IEnumerable<ICustomer> GetCustomerList();
}
ICustomerListModel:
public interface ICustomerListModel
{
ObservableCollection<ICustomer> Customers
{
get;
}
}
CustomerListModel
public class CustomerListModel : ICustomerListModel
{
private readonly IDatabase database;
private readonly ObservableCollection<ICustomer> customers;
public CustomerListModel(IDatabase database)
{
this.database = database;
this.customers = new ObservableCollection(database.GetCustomerList());
}
public ObservableCollection<ICustomer> Customers
{
get
{
return this.customers;
}
}
}
CustomerListViewModel
public class CustomerListViewModel
{
private readonly ICustomerListModel customerListModel;
public CusomterListViewModel(ICustomerListModel customerListModel)
{
this.customerListModel = customerListModel;
}
public ObservableCollection<ICustomer> Customers
{
get
{
return this.customerListModel.Customers;
}
}
}
So what you can see here is that I have extracted an interface for the database which I request the information from, this means that I don't care about the implementation of the IDatabase, I just now that it provides me with a collection of ICustomer's when I call GetCustomerList().
So I inject a copy of the IDatabase into the CusomterListModel class which I can then query knowing that I'll get what I want back correctly. I then inject the ICustomerListModel into the ICustomerListViewModel so that the collection can be presented to the View.
So to test the CustomerListModel I would have a test like:
[Fact]
public void Customers_IsCorrectlyInitialisedAtStartup_Test()
{
var databaseMock = new Mock<IDatabse>();
var customer = new Customer();
var customers = new [] { customer };
databaseMock.Setup(mock => mock.GetCustomerList())
.Returns(customers);
var sut = new CustomerListModel(databaseMock.Object);
Assert.Equal(customers, sut.Customers);
}
In this I have mocked a version of the IDatabase, now you can see how I don't care in the version of CustomerListModel what IDatabase I have as long as I can call GetCustomerList(). This has a setup to return a ICustomer when a call to GetCustomerList() is called. Finally I am asserting that the Customers collection was correctly populated with the returns of the IDatabase call.
Unit testing is a fine art, difficult to understand at first but when you get it working at first you'll pick it up quickly. Some things you may wish to look at to help you with generating unit testable code and actually testing:
Solid Principles, principles that every Software Engineer should at least be familiar with, will help generating code that is testable.
Dependency Injection, the wiki-page on Dependency Injection outlining the pros and cons to injecting the dependency into a constructor, when and how to use it in further examples.
Moq, a friendly and easy to use mocking framework for C#, which I used as part of my example above.
I have some issue. Im writing some unit test in my project but i don't know how to test my CRUD methods.. Maybe they are not testable ;/
This is one of my methods:
public static void IncrementInvalidLoginColumn(string login)
{
User user;
using (DTContext context = new DTContext())
{
try
{
user = context.Users.Where(u => u.Login.CompareTo(login) == 0).FirstOrDefault();
if (user.InvalidLogins < 3)
{
user.InvalidLogins = user.InvalidLogins + 1;
}
context.SaveChanges();
}
catch
{
}
}
}
Maybe someone will have idea what should i do.
It depends on what you mean by "unit" test. If you don't want your test to hit the database then your method is not testable (or at least not without some refactoring).
If hitting the database is acceptable (which would actually be an integration test) then you can definitely test your method.
Here are some steps:
1. Arrange the initial data. You use an instance of the DTContext directly in the test to put the system in a predefined state (basically you write some user records in the database)
You run the method you want to test (which in fact uses its own instance of the DTContext)
You use DTContext again to read the user information directly from the database and assert that the InvalidLogins property has incremented.
You need to make sure you delete any data that you put in manually.
This is the gist of DI:
public class Example {
private IDatabaseGateway myDatabase;
public Example(IDatabaseGateway myDb) {
myDatabase = myDb;
}
public void DoStuff() {
...
myDatabase.GetData();
...
}
}
You give your business class an abstraction of the database via the constructor, that is you inject your dependencies in the class that needs them.
Once you have this in place, in production code you pass in the constructor a concrete instance of IDatabaseGateway that goes to the actual database.
In the case of a unit test you pass it a mock instance of the same interface. The mock is a special object that you can setup/configure to return what you want. Various libraries exist for mocking (an easy one is Moq).
However without modifying your code too much, it is better to stick with integration testing that hits the database. It will give you a simple and valid test.
Especially since there are some pitfalls in mocking the DbContext in EF (ex. some queries may not work when you will use them in production, testing updates in EF with mocks is a bit trickier).
Ok so i read all of your posts and they was very helpful.
I use MOQ framework and this is example how i do it.
This is how Liviu M. told me to do for example:
public class CRUDclass
{
private DTContext _context;
public CRUDclass(DTContext myObj)
{
_context = myObj;
}
}
We have CRUD Class which are doing operations directly on our database. We have constructor with one argument and private field. This our context :)
This is (for example) my method in CRUDclass:
public bool AddUser(User user)
{
try
{
_context.Users.Add(user);
_context.SaveChanges();
return true;
}
catch
{
return false;
}
}
Ovecourse he have our DTContext class witch DBSet becouse i using entity framework. And after that i am able to write some test method:
[TestMethod]
public void Should_Add_User()
{
var mockSet = new Mock<DbSet<User>>();
var mockContext = new Mock<DTContext>();
mockContext.Setup(m => m.Users).Returns(mockSet.Object);
var usrCRUD = new UserCRUD(mockContext.Object);
var usr = new User();
usr.Login = "Login_Name";
usr.Email = "loginName#test.com";
usr.Password = "***";
usr.InvalidLogins = 0;
usr.RememberID = 0;
usrCRUD.AddUser(usr);
mockSet.Verify(m => m.Add(It.Is<User>(arg => arg.Login == "Login_Name")));
mockContext.Verify(m => m.SaveChanges(), Times.Once());
}
At first a have to set my fake object (Mock>).
This test method checks if our user was added to Mock :)
I hope it can help somebody, if anything will be unclear please write a question :)
The idea of unit tests is to test your ifs, switches, etc., not the database operations.
In your case you need an interface that is an abstration of DTContext. In the simplest case it might look as the following.
public interface IObjectContext : IDisposable
{
IEnumerable<User> Users { get; }
}
In more complicated cases you may need to use IQueryable<T> or IObjectSet<T> instead of IEnumerable<T>.
Add a partial class declaration of DTContext and make it implement IObjectContext. Add a constructor to the class that contains the method IncrementInvalidLoginColumn with a parameter of type IObjectContext. Now you can inject any instance of IObjectContext instead of creating it in your class. This instance can be a DTContext or a mock for testing. Your class is ready to be tested without connection to a real database.
NB. In case of instances of IDisposable it's better to inject a Func<IObjectContext> instead of IObjectContext. Then you can create an instance for each operation and dispose it immediately after.
If there are CRUD operations in your code then I will recommend to use MOQ framework for unit testing. Below links are quite helpful:
Quick Start
Code Project
Ideally you would inject your DTContext rather than creating a new one every time that the method is called. That way you could mock that object in your unit test and verify that it is called as expected.
Your constructor would look something like:
private readonly IDTContext _context;
public CrudClass(IDTContext context)
{
_context = context
}
With your method now looking like
public static void IncrementInvalidLoginColumn(string login)
{
User user;
try
{
user = _context.Users.Where(u => u.Login.CompareTo(login) == 0).FirstOrDefault();
if (user.InvalidLogins < 3)
{
user.InvalidLogins = user.InvalidLogins + 1;
}
_context.SaveChanges();
}
catch
{
// Handle errors
}
}
And then in your test, if you were using a framework like Moq, you would basically script how that object would behave and test against that. For instance, setting up the mocked IDTContext to always return the same user for your Users collection and SaveChanges() method will write the number of invalid logins to a variable that you could then test against.
Given I have a controller class as such:
public class ResourceController : AuthorizedController
{
public virtual string Resource()
{
//do magic
}
public virtual string ResourceParent()
{
var url = Resource();
return url;
}
}
}
With the test harness:
[Subject(typeof (ResourceController))]
public class When_I_want_the_parent_resource : WithSubject<ResourceController>
{
private static readonly string ParentUrl = "/organizations/1";
private static readonly string ResourceUrl = "/organizations/1/contacts/1";
private static string _result;
private Establish context = () =>
{
The<ResourceController>()
.WhenToldTo(x => x.Resource())
.Return(ResourceUrl);
};
private Because of = () => _result = Subject.ResourceParent();
private It should_match_the_expected_parent_url = () =>
_result.ShouldEqual(ParentUrl);
}
This unit test will fail because Subject.ResourceParent() will return null because Machine.Fakes has automocked this method. As a temporary workaround I just removed the virtual keyword from ResourceParent to be able to test my code. I assume there has to be a real solution for me to tell Machine.Fakes to not override ResourceParent()
actually there isn't a "real" solution in Machine.Fakes for this. I would argue that you need to reconsider you're fixture design.
First of all, as Tim already pointed out, you you should't fake any methods on the subject itself. Instead you should fake the dependencies of your controller and use your controller as-is in specifications. The intended usage of the "The" method is to access the dependencies of the subject under specification, but what you try in your spec is to access the subject itself. I think that's where things go wrong. The <ResourceController> and subject are actually separate instances. That's why you configured interaction doesn't happen.
Just some options to fix this in your code:
Introduce a new dependency in your code which you can stub via "The"
If the first seems to heavyweight, you could also replace the virtual method with a Func<string> dependency for your controller and use the "Configure" method to inject a specification specific one for your spec.
HTH,
Bjoern
If you're testing a controller, then perhaps you shouldn't be creating mocks or fakes of that controller. Otherwise you're just testing a mock and the test doesn't really have any validity.
Mock or fake the dependencies of the controller. Test the real controller.
In the end I ended up pulling this test out of Machine.Fakes and put it into a regular unit test. Then I just used Moq directly to configure the HttpRequestBase to seed data I needed and then just manually created my controller class and invoked methods on it.