I'm trying to get my controller in a unit test to return a mock file when Request.Files[0] is called
From other posts on this site I've put together:
[TestMethod]
public void CreateFileInDatabase()
{
var repository = new MocRepository();
var controller = GetController(repository);
HttpContextBase mockHttpContext = MockRepository.GenerateMock<HttpContextBase>();
HttpRequestBase mockRequest = MockRepository.GenerateMock<HttpRequestBase>();
mockHttpContext.Stub(x => x.Request).Return(mockRequest);
mockRequest.Stub(x => x.HttpMethod).Return("GET");
var filesMock = MockRepository.GenerateMock<HttpFileCollectionBase>();
var fileMock = MockRepository.GenerateMock<HttpPostedFileBase>();
filesMock.Stub(x => x.Count).Return(1);
mockRequest.Stub(x => x.Files).Return(filesMock);
var t = mockHttpContext.Request;
var automobile = new Automobile{ automobileNumber = "1234" };
controller.ControllerContext = new ControllerContext(mockHttpContext, new RouteData(), controller);
controller.Create(automobile);
}
When I'm in the controller during a test and call Request.Files I get the filesMock great.
However I want to be able to call Request.Files[0] and get a mock File which I can pass as a parameter to a method.
I haven't done much mocking before so any help would be appreciated!
Your filesMock object is a mock, therefore it have no idea how to resolve Files[0]. You need to tell it what to return, if someone asks for the first file:
filesMock.Stub(x => x[0]).Return(fileMock);
Add the above line after the creation of the fileMock object and the code works :)
The easiest way is to add an abstraction over the Request.Files[0] via an interface and object that actually calls out to Request.Files[0]
Note: I'm not actually sure what the datatype is for Request.Files[0], just using IFile as an example.
public interface IFileRetriever
{
IFile GetFile();
}
public class FileRetriever
{
public IFile GetFile()
{
return Request.Files[0];
}
}
Obviously suit the interface and real implementation to your use case, it will probably not be what is above...
In your class that currently calls out to Request.Files[0] just take in the IFileRetriever as a dependency, which is straightforward to mock out in Rhino Mocks (or any mocking/faking framework)
Related
Have I written an untestable method? As the library I am using has an important method which is implemented as an extension method, it seems like I am unable to fake it. And thus, unable to test my method.
First, I'll set out a truncated version of the method I want to test.
Then, I'll set out the attempt I have made to fake it using FakeItEasy.
The method uses caching and it is the call to the static method in the caching library LazyCache which I am struggling to fake:
public async Task<BassRuleEditModel> GetBassRuleEditModel(
int facilityId,
int criteriaId,
int bassRuleId,
BassRuleEditDto bassRuleEditDto)
{
var url = _bassRuleService.GetServiceConnectionForFacility(facilityId).Url;
var dto = bassRuleEditDto ?? _bassRuleService.GetBassRuleEditDto(bassRuleId);
var bassRuleEditModel = new BassRuleEditModel
{
...
LocationList = await GetLocations(url),
...
};
...
return bassRuleEditModel;
}
private async Task<IEnumerable<SelectListItem>> GetLocations(string url)
{
var cacheKey = string.Concat(CacheKeys.Location, url);
var selectList = await _appCache.GetOrAddAsync(cacheKey, async () =>
{
return new SelectList(await _tasksAndPrioritiesService.ReturnLocationsAsync(url), NameProperty, NameProperty);
}
, CacheKeys.DefaultCacheLifetime);
return selectList;
}
It is the GetOrAddAsync method which is an extension method.
I just want the fake to return from the cache an empty SelectList.
Note, the AppCache and all dependencies are injected using constructor injection.
The unit test which I have written, where I have tried to fake the AppCache is:
[Fact]
public async Task Un_Named_Test_Does_Stuff()
{
var url = "http://somesite.com";
var referrer = new Uri(url);
var facilityId = GetRandom.Id();
var serviceConnectionDto = new ServiceConnectionDto
{
Url = "http://google.com" // this url does not matter
};
var cacheKey = string.Concat(CacheKeys.Location, serviceConnectionDto.Url);
A.CallTo(() => _bassRuleService.GetServiceConnectionForFacility(facilityId)).Returns(serviceConnectionDto);
A.CallTo(() => _urlHelper.Content("~/ServiceSpec/ListView")).Returns(url);
A.CallTo(() => _appViewService.GetReferrer(url)).Returns(referrer);
A.CallTo(() => _appCache.GetOrAddAsync(cacheKey, A<Func<Task<SelectList>>>.Ignored))
.Returns(Task.FromResult(new SelectList(Enumerable.Empty<SelectListItem>().ToList())));
var editModel = await
_bassRuleService.GetBassRuleEditModel(GetRandom.Int32(),
GetRandom.Int32(),
GetRandom.Int32(),
null
);
var path = editModel.Referrer.AbsolutePath;
editModel.Referrer.AbsolutePath.ShouldBe(referrer.AbsolutePath);
}
I create the fakes in the constructor of the test (using xUnit):
public BassRuleQueryServiceTests()
{
_currentUser = A.Fake<ICurrentUser>();
_bassRuleService = A.Fake<IBassRuleService>();
_tasksAndPrioritiesService = A.Fake<ITasksAndPrioritiesService>();
_appViewService = A.Fake<IAppViewService>();
_urlHelper = A.Fake<IUrlHelper>();
_applicationDateTime = A.Fake<IApplicationDateTime>();
_appCache = new MockCacheService();
}
The error from running the test is:
Message:
FakeItEasy.Configuration.FakeConfigurationException :
The current proxy generator can not intercept the method LazyCache.AppCacheExtenions.GetOrAddAsync1[Microsoft.AspNetCore.Mvc.Rendering.SelectList](LazyCache.IAppCache cache, System.String key,
System.Func1[System.Threading.Tasks.Task`1[Microsoft.AspNetCore.Mvc.Rendering.SelectList]] addItemFactory) for the following reason:
- Extension methods can not be intercepted since they're static.>
I get the fact that faking a static method is not on. I'm looking for solutions.
Do I need to pressure library authors to not use extension methods? (Facetious question)
Cheers
As you have correctly noted, extensions are static methods, and static methods can't be faked.
Extension methods are often just wrappers to simplify operations on the type they extend; it appears to be the case here. The GetOrAddAsync extension method you're calling ends up calling the IAppCache.GetOrAddAsync method. So you should fake that method instead.
A.CallTo(() => _appCache.GetOrAddAsync(cacheKey, A<Func<ICacheEntry, Task<SelectList>>>.Ignored))
.Returns(new SelectList(Enumerable.Empty<SelectListItem>().ToList()));
It's not very convenient, because it means you need to know what the extension method does, but there's no way around it (short of creating an abstraction layer around the library, but LazyCache is already an abstraction around Microsoft.Extensions.Caching.Memory...)
(btw, you don't need Task.FromResult; the Returns method has an overload that accepts a T when you configure a method returning a Task<T>)
Also, if you're going to return an empty sequence anyway, you don't need to configure the method at all. The default behavior of FakeItEasy will be to return a dummy IEnumerable<SelectListItem> which is empty.
As an alternaive to the excellent answer by #Thomas Levesque, two other alternatives would be:
not to mock the cache at all - use the a real CachingService as it runs in memory and so would be perfectly reasonable to include in the tests.
Use the mock instance MockCachingService cache that ships with LazyCache for this purpose.
See https://github.com/alastairtree/LazyCache/wiki/Unit-testing-code-using-LazyCache for an example.
I am getting this error when I run my test: System.NotImplementedException : The member 'IQueryable.Provider' has not been implemented on type 'DbSet' ...'
I saw this blog post on creating a fakeDbSet but that was before EF6. Is there a better way to handle this with EF 6?
[Test]
public void Edit_ShouldCall_DbContext_Entry()
{
//arrange
var request = Builder<EditGroupRequest>.CreateNew().Build();
fakeDbSet.Stub(x => x.FirstOrDefault(y => y.ReportGroupNameKey == request.Key)).Return(new MyObject());
//act
_sut.Edit(request);
//assert
_contextFake.AssertWasCalled(x => x.Entry(Arg<MyObject>.Is.Anything).Property(y => y.ReportGroupName).CurrentValue = request.Name);
}
Although DBSet implements IQueryable, IDbSet... the object generated by the mock engine is not implementing them.
A possible solution is using a Mocking framework that supports building mocks that implement many interfaces like the one pointed out in another thread (Substitute):
Mocking DBSet, EF Model First
Here you have an utility function to build a mocked DBSet which data is stored on a generic list:
public static DbSet<T> BuildMockedDbSet<T>(List<T> data) where T : class
{
IQueryable<T> queryable = data.AsQueryable();
DbSet<T> fakeDbSet = Substitute.For<DbSet<T>, IQueryable<T>>();
((IQueryable<T>)fakeDbSet).Provider.Returns(queryable.Provider);
((IQueryable<T>)fakeDbSet).Expression.Returns(queryable.Expression);
((IQueryable<T>)fakeDbSet).ElementType.Returns(queryable.ElementType);
((IQueryable<T>)fakeDbSet).GetEnumerator().Returns(queryable.GetEnumerator());
fakeDbSet.AsNoTracking().Returns(fakeDbSet);
return fakeDbSet;
}
Hope it helps.
I am currently having issues with testing a method which my controller uses which is mocked. it has a return type of an specific enum. I am currently always getting back from this mocked method the default enum value, not the value that I have specified it to return. Am i missing something? I have tried both Moq and JustMock lite with the same results. JustMock lite example below.
Hopefully i haven't made any mistakes in copying the code, I have changed all the names of the objects so apologies for that.
Here is part the unit test:
var returnStatus = ExampleEnum.Invalid;
//Mock the client
var client = Mock.Create<ITestInterface>();
Mock.Arrange(() => client.ValidateSomething(Guid.NewGuid()))
.Returns(returnStatus).MustBeCalled();
var testController = new TestController(client);
var result = testController.DoSomething(Guid.NewGuid().ToString()) as ViewResult;
Here are the relevant bits from the controller:
private ITestInterface _client { get; set; }
public TestController(ITestInterface client)
{
_client = client;
}
Here is part of my controller action:
public ActionResult DoSomething(string id)
{
Guid token;
if(!string.IsNullOrEmpty(id) && Guid.TryParse(id, out token))
{
using (var client = _client)
{
ApplicationUser applicationUser;
var status = client.ValidateSomething(token);
switch (status)
{
The client is mocked correctly but the "status" property getting returned is always ExampleEnum.DefaultValue not the value i have specified to be the result.
I hope i have provided enough information. Any help much appreciated.
You probably did your setup wrong.
Guid.NewGuid() returns a new random GUID, so the GUID you use to setup your mock and the GUID you use to call the DoSomething method will never be the same.
You should do something like:
var guid = Guid.NewGuid()
...
Mock.Arrange(() => client.ValidateSomething(guid))
.Returns(returnStatus).MustBeCalled();
...
var result = testController.DoSomething(guid.ToString()) as ViewResult;
using the same GUID for the mock and for the call to DoSomething.
I don't know about JustMock, but with Moq you could also simply use It.IsAny to match all GUIDs:
client.Setup(c => c.ValidateSomething(It.IsAny<Guid>())).Returns(returnStatus);
say I have two models that extend from Eloquent and they relate to each other. Can I mock the relationship?
ie:
class Track extends Eloquent {
public function courses()
{
return $this->hasMany('Course');
}
}
class Course extends Eloquent {
public function track()
{
return $this->belongsTo('Track');
}
}
in MyTest, I want to create a mock of course, and return an instance of track, by calling the track property, not the track instance (I don't want the query builder)
use \Mockery as m;
class MyTest extends TestCase {
public function setUp()
{
$track = new Track(array('title' => 'foo'));
$course = m::mock('Course[track]', array('track' => $track));
$track = $course->track // <-- This should return my track object
}
}
Since track is a property and not a method, when creating the mock you will need to override the setAttribute and getAttribute methods of the model. Below is a solution that will let you set up an expectation for the property you're looking for:
$track = new Track(array('title' => 'foo'));
$course = m::mock('Course[setAttribute,getAttribute]');
// You don't really care what's returned from setAttribute
$course->shouldReceive('setAttribute');
// But tell getAttribute to return $track whenever 'track' is passed in
$course->shouldReceive('getAttribute')->with('track')->andReturn($track);
You don't need to specify the track method when mocking the Course object, unless you are also wanting to test code that relies on the query builder. If this is the case, then you can mock the track method like this:
// This is just a bare mock object that will return your track back
// whenever you ask for anything. Replace 'get' with whatever method
// your code uses to access the relationship (e.g. 'first')
$relationship = m::mock();
$relationship->shouldReceive('get')->andReturn([ $track ]);
$course = m::mock('Course[track]');
$course->shouldReceive('track')->andReturn($relationship);
I'm following the accepted answer in this question but I'm getting a NullReferenceException.
What I need is having a partial mock stub a property (both getter and setter) to behave like a stub (as a simple automatic property). Currently I am able to stub the getter but not the setter.
Is this possible?
EDIT: this is a simple example, I hope it helps explaining my problem.
public class SomeClass
{
public virtual string SomeProperty
{
get{ return SomeMethodDependingOnDBOrAspSession(); }
set{ SomeMethodDependingOnDBOrAspSession(value); } // I want to avoid calling this setter implementation
}
}
var partialMock = MockRepository.GeneratePartialMock<SomeClass>();
partialMock.Stub(p => p.SomeProperty); // I want SomeProperty to behave as an automatic property
When using a PartialMock you can get auto-implemented property like behavior by using PropertyBehavior feature of Rhino Mocks. Given the class in your question, the following nunit test passes for me.
[Test]
public void TestPartialMock()
{
var someClass = MockRepository.GeneratePartialMock<SomeClass>();
someClass.Stub(x => x.SomeProperty).PropertyBehavior();
string val = "yo!";
Assert.DoesNotThrow(() => someClass.SomeProperty = val);
Assert.AreEqual(val, someClass.SomeProperty);
}
If you don't need a PartialMock you could use a Stub which has property behavior by default. You'd simply replace the first two lines of the test with:
var someClass = MockRepository.GenerateStub<SomeClass>();