I want to write a unit test which tests the function of a class called UploadedFile.
The problem I face is this class' static constructor uses HttpContext.Current property and because I am running my unit test from a class library I do not have an HttpContext at the testing time.
Look at my static constructor:
static UploadedFile()
{
if (HttpContext.Current == null)
throw new Exception("web server not available");
HttpServerUtility server = HttpContext.Current.Server;
// SET UploadedFileMappingFile Names:
_resourceFileNames = new StringDictionary();
_resourceFileNames[_suppoertedFileStructures] = server.MapPath(SupportedUploadedFileStructures);
_resourceFileNames[_supportedFileStructuresXSD] = server.MapPath(SupportedUploadedFileStructuresXSD);
_resourceFileNames[UploadedFileEnum.UploadedFileFormatENUM.CSV.ToString()] = server.MapPath(UploadedFileColumnMap);
}
What should I do in my testing environment so that HttpContext.Current won't be null and I can successfully set this:
HttpServerUtility server = HttpContext.Current.Server;
You shouldn't use HttpContext.Current directly in your function as it is close to impossible to unit test, as you've already found out. I would suggest you using HttpContextBase instead, which is passed either in the constructor of your class or as an argument to the method you are testing. This will allow the consumers of this class to pass a real HttpContextWrapper and in your unit test you can mock the methods you need.
For example here's how you could call the method:
var wrapper = new HttpContextWrapper(HttpContext.Current);
Foo.UploadedFile(wrapper);
And in your unit test (using Rhino Mocks):
var contextMock = MockRepository.GenerateMock<HttpContextBase>();
// TODO: Define expectations on the mocked object
Foo.UploadedFile(contextMock);
Or, if you prefer, use Constructor Injection.
Related
I'm writing an unit test(using NUnit & MOQ) for an action method MethodUnderTest which uses HttpContext internally to do some functionality. I'm setting up a fake hosting environment by calling InitializeHostingEnvironment where I'm initializing the session like:
public static HttpSessionState InitializeSession()
{
var httpRequest = new HttpRequest("", "http://localhost/", "");
var stringWriter = new StringWriter();
var httpResponse = new HttpResponse(stringWriter);
var httpContext = new HttpContext(httpRequest, httpResponse);
HttpContext.Current = httpContext;
HttpContext.Current.Items.Clear();
HttpSessionState session = (HttpSessionState)ReflectionHelper.Instantiate(typeof(HttpSessionState), new Type[] { typeof(IHttpSessionState) }, new FakeHttpSessionState());
HttpContext.Current.Items.Add("AspSession", session);
return session;
}
public static void InitializeHostingEnvironment(string userName, string password)
{
// lines of code
InitializeSession();
}
I'm calling the InitializeHostingEnvironment() from my Test Method like so:
public static void Test_MethodUnderTest()
{
InitializeHostingEnvironment(UN, PW);
MethodUnderTest(param1, param2, param3); -- getting exception while trying to execute this line
}
While trying to execute the line MethodUnderTest(param1, param2, param3);, I'm getting an exception - System.ArgumentNullException - Value cannot be null. Parameter name httpBrowserCapabilities. Stack trace is given below:
Since the exception says httpBrowserCapabilities is null, I tried to initialize it like HttpContext.Current.Request.Browser = new HttpBrowserCapabilities(); inside the InitializeSession() method, but now, I'm getting another exception:
What should I do now? Is the way I'm initializing HttpContext wrong? please advise.
I'm writing an unit test(using NUnit & MOQ) for a method MethodUnderTest which uses HttpContext internally to do some functionality.
Right. Don't do that. The controller should be the only method that accesses the HttpContext, and it should extract the data needed for your MethodUnderTest and use the to write to the HttpContext.
Structuring your code so that each method has a single responsibility is fundamental to writing testable code.
Does any one know what type of attribute can we use to run all of the unit tests independently? for example in following we used [Fact] attribute but it does not make tests run independently. Is there any other type attribute that we can use to initialize data at beginning of each test and make tests run independently from each other? How can I run unit tests independently in visual studio code?
namespace Tests
{
public class TestCategory
{
//Test Get() Method
[Fact]
public void Get_WhenCalled_ReturnsAllCategories()
{
//Arrange
//create _options
var _Options = new DbContextOptionsBuilder<MyContext>()
.UseInMemoryDatabase("Data Source=MyCart.db").Options;
var Context = new MyContext(_Options);
Context.CategoryTestData();//We make sure that dummy data has been added
var Controller = new CategoryController(Context);//pass context inside controller
//Act
var Results = Controller.Get();//call Get() function inside Category controller
//Assert
Assert.NotNull(Results);
}
//Test GetById() Method
//When valid Id is passed
[Fact]
public void GetById_ExistingIntIdPassed_ReturnsOkResult()
{
//Arrange
var _Options = new DbContextOptionsBuilder<MyContext>()
.UseInMemoryDatabase("Data Source=MyCart.db").Options;
var Context = new MyContext(_Options);//pass _Options into context
var Controller = new CategoryController(Context);//pass Context inside controller
//Act
var OkResult = Controller.GetById(1);//1 is valid Id
//Assert
Assert.IsType<OkObjectResult>(OkResult.Result);
}
}
}
If you are using the Visual Studio IDE you should try to check the
Run Tests In Parallel on Test Explorer window.
And then your tests should run in parallel.
If you add a constructor to your class you can set up "initialisation" data etc..
There is no [Attribute], if you know other test frameworks, you can have a look at a comparison list to see how the [Attributes] compares to xUnit.
When you look at *Note 3 on that page you will see it describes the use of an IClassFixture<T> interface that can be used to share context between tests
For parallel testing you can configure it in the configuration of xUnit.
I finally found the answer here:
How to isolate EF InMemory database per XUnit test
Actually we want that our context not to be shared between the tests hence we have to make a new context at the beginning of each test like this:
using (var Context = new myContext(CreateNewContextOptions()))
{
//here we implement Arrange, Act, and Assert parts
}
CreateNewContextOptions() is actually a function that helps us to create a new context.
I'm looking at the unit tests for SignalR and noticed one of the tests uses Moq to create a mock HubConnection:
[Fact]
public void HubCallbackClearedOnFailedInvocation()
{
var connection = new Mock<HubConnection>("http://foo");
var tcs = new TaskCompletionSource<object>();
tcs.TrySetCanceled();
connection.Setup(c => c.Send(It.IsAny<string>())).Returns(tcs.Task);
var hubProxy = new HubProxy(connection.Object, "foo");
var aggEx = Assert.Throws<AggregateException>(() => { hubProxy.Invoke("foo", "arg1").Wait(); });
var ex = aggEx.Unwrap();
Assert.IsType(typeof(TaskCanceledException), ex);
Assert.Equal(connection.Object._callbacks.Count, 0);
}
However, when I try and do the same with a slightly different mocking framework, RhinoMocks, it complains that the method isn't virtual:
[Test]
public void ShouldCreateBrokerWithHubConnection()
{
//Arrange
var url = "http://localhost6790";
var hubProxy = MockRepository.GenerateMock<IHubProxy>();
var hubConnection = MockRepository.GenerateMock<HubConnection>(url);
hubConnection.(c => c.CreateHubProxy("ArtemisClientHub")).Return(hubProxy);
... (more code)
}
System.InvalidOperationException : Invalid call, the last call has been used or no call has been made (make sure that you are calling a virtual (C#) / Overridable (VB) method).
Is this just a shortcoming of RhinoMocks compared to a newer library like Moq?
My tip is to use the none concrete types from your code and inject the concrete types using a Ioc. The signalr dot net client however is missing a DependencyResolver unlike the server. I rolled my own to get around this, you can check out the code here (But in your case you can use any Ioc like Ninject, autofac etc)
https://github.com/AndersMalmgren/SignalR.EventAggregatorProxy/blob/master/SignalR.EventAggregatorProxy.Client.DotNet/Bootstrap/DependencyResolver.cs
The hub connection and proxy is a bit hard to abstract since you are dependent on the concrete types to create the proxy. I solved it with abstracting the creation of the hub proxy to a factory interface that returns a IHubProxy that can be easily mocked.
Look here
https://github.com/AndersMalmgren/SignalR.EventAggregatorProxy/blob/master/SignalR.EventAggregatorProxy.Client.DotNet/Bootstrap/Factories/HubProxyFactory.cs
All examples are taken from my dot net client for this library
https://github.com/AndersMalmgren/SignalR.EventAggregatorProxy
I'm trying to create some unit tests for an application I've recently inherited. Currently using NSubstitute because that's what the previous programmer used, but I'm not attached to it.
The method I'm testing calls the DataService class' Create method.
Calling Create Method
var contactProductLink = this.dsService.Create<ContactProductLink>(x =>
{
x.ContactRoleId = prod.RoleId;
x.ContactId = contactViewModel.ContactId;
x.ProductId = prod.ProductId;
x.Active = true;
x.InsertDate = DateTime.Now;
x.InsertUserId = user.employeeId;
x.UpdateDate = DateTime.Now;
x.UpdateUserId = user.employeeId;
});
DataService Create Method:
public TEntity Create<TEntity>(Action<TEntity> propertySetter = null) where TEntity : class
{
var tEntity = this.Context.Create<TEntity>();
if (propertySetter != null)
{
propertySetter(tEntity);
}
return tEntity;
}
The approach I've taken (and maybe there's a better way) is to use NSubstitute to mock the DataService. When I'm doing my assertions at the end, I'm checking to make sure that the Create method was called:
mockDataSupplierService.Received().Create<ContactProductLink>(Arg.Any<Action<ContactProductLink>>());
However, I'd like to also verify the input that was sent to the method is correct, and here's where I'm running into trouble. I can get the System.Action object that was passed to the Create method, but I can't figure out how to pull out the parameters (such as ContactRoleId, ContactId, etc. as posted in the calling create method code snippet).
So after all of that what I'm asking is:
How can I access those input parameters so I can verify the correct arguments are being passed to the data service? Is it even possible?
Is there a better way to do this than what I'm currently trying to do?
Solution
//Arrange
mockDataSupplierService.Create<ContactProductLink>(Arg.Do<Action<ContactProductLink>>(x=> actionToPopulateEntity = x));
//Assert
mockDataSupplierService.Received().Create<ContactProductLink>(Arg.Any<Action<ContactProductLink>>());
var entity = new ContactProductLink();
actionToPopulateEntity.Invoke(entity);
Assert.AreEqual(ExpectedContactId, entity.ContactId);
How can I access those input parameters so I can verify the correct arguments are being passed to the data service? Is it even possible?
Essentially you can't, as it is not possible to extract "code" details from action (consider what happens when you pass an action that doesn't set any properties - this is totally legal, but would break hypothetical mechanism).
However, you can try this instead:
Create entity with initial values
Use Arg.Invoke argument, telling NSubstitute to use chosen object as action parameter
Verify that entity properties values changed
For example:
// Arrange
var entity = new ContactProductLink
{
ContactRoleId = // ...
// ...
};
mockDataSupplierService
.Create<ContactProductLink>(Arg<ContactProductLink>.Invoke(entity));
// Act
// ...
Assert.That(entity.ContactRoleId, Is.EqualTo(2));
// ...
I'm still trying to get my head around mocking. Right now, I'm trying to test my Save method on my UserService. As such, I'm mocking out my IRepository which my UserService class uses.
What I don't get is... if i normally save this user to my DB/Repository, it magically gets an Identity, which it then gets set, into my instance object. No rocket science stuff, here.
What I don't understand is, how do i mock this? should I care? I thought I should. Or.. is it that i don't care about that .. because I'm just making sure that the Repository method is called .. not so much that I get the correct data BACK from it.
Here's my pseudo unit test code. (unit test, not integration test .. hence the mock'd repository)...
[TestMethod]
public void GivenANewUserWithValidData_Save_ReturnsTheSameNewUserWithAUserIdDetermined()
{
// Arrange.
var const string passwordSalt = "V4BXAhmHq8IMvR7K20TgoQ=="
var user = new User
{
DisplayName = "Test",
Email = "foo#foo.com",
PasswordSalt = passwordSalt ,
Password = "foobar".ToSha2Hash(passwordSalt)
};
var mockUserRepository = new Mock<IRepository<User>>();
mockUserRepository.Setup(x => x.Save(It.IsAny<User>())).Verifiable();
// Configure this repo in our Dependency Injection.
ObjectFactory.Inject(typeof (IRepository<User>), mockUserRepository.Object);
// Act.
using (new TransactionScope())
{
UserService.Save(user);
UnitOfWork.Commit(); // <-- not sure about this.. currently it's still
// an EntityFramework context.
// I need to change this to.. something??
// Assert.
Assert.IsNotNull(user);
Assert.IsTrue(user.UserId > 0);
}
}
and the user service looks like this..
public class UserService : IUserService
{
public UserService(IRepository<User> userRepository,
ILoggingService loggingService)
{
// .. snip ..
public void Save(User user) { .. }
}
}
Any suggestions?
If you are unit testing UserService.Save(), then all your test should care about is that the repository is called. It's the responsibility of the repository tests to verify that an object is saved correctly.
That's actually something easy to do. You're setting up the Mock object like so:
mockUserRepository.Setup(x => x.Save(user)).Callback(() => user.UserId = 10);
// mocking the value of 10 being insterted into the key
You can even continue using It.IsAny() if you want in the setup, but basically all you need to do is attach the callback to the end of your setup method.
> 1) How should I test a [UserService.]Save method?
Should I care about the result? and
> 2) If i do care about #1 .. then how do i mock the
result also, so I can test that
If the repository is responsible to do the Identity-Magic then it makes no sense to mock this functionality in a test and then verify that this functionality has happened in the test. You want to test the UserService and not the IRepository-mock. The mock is there to crate a fake repository with just enought intelligence that the service does not crash and gets all requirements for the testcase. In this case I do not think that Identity-Magic is required by the service.
If the service is responsible to do the Identity-Magic then it makes sence to test if the id has been set.