Scenario
I would like to check if a component (the sut) logs error in a particular condition. The ILogger interface constructor injected into the component, and the Error method has 4 overloads.
So I create a ILogger mock in the Arrange and using it in the Act.
I should not expect which overload the sut is using, just would like to expect and check if any of the overload called. (that would extremely white-box, and expects far more than the functional spec.)
Question
Currently my conclusion is that I can not utilize the .Received instead I must install callbacks for all the 4 overloads, and set a variable inside them, and in the Assert part I examine that variable.
Is any simple way to do this what I missed?
(example)
[TestMethod]
public void ShouldLogErrorIfEmailIsInvalid2()
{
// Arrange
var testEmailAddress = "dummy";
//var mock = new Mock<IEMailValidator>();
var validator = Substitute.For<IEMailValidator>();
validator.Validate(Arg.Any<string>()).Returns(false);
var logger = Substitute.For<ILogger>();
var sut = new CustomerController(validator, logger);
var customer = new Customer() { Email = testEmailAddress };
// Act
sut.Post(customer);
// Assert
// *** Here I do not want to expect a specific overload of Error, instead any of the 4 overloads satisfies the expectation
logger.Received(1).Error(Arg.Is<string>( m => m.ToLower().Contains("email")), Arg.Any<object>());
}
NSubstitute does not have built-in syntax for this, but it is possible to query all ReceivedCalls() and manually assert on this.
For example:
var errorCalls = logger.ReceivedCalls()
.Where(x => x.GetMethodInfo().Name == nameof(logger.Error))
.Where(x => (x.GetArguments()[0] as string).ToLower().Contains("email"));
Assert.AreEqual(1, errorCalls.Count());
If this this is something you need frequently you could implement some helper methods and package this up into something fairly concise I think. (Maybe static void ReceivedCallToAny(this object substitute, string methodName, Func<object[], bool> requiredArgs) with some helpers like T GetItemAs<T>(object[] items) to access arguments?)
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'm using the MockingContainer<T> to automatically set up my dependencies. How do I assert that a property on one of those dependencies gets set?
[SetUp]
public void SetUp()
{
//arrange
_baseUrl = "http://baseUrl";
_container = new MockingContainer<ApiInteractionService>();
_container.Arrange<IConfigService>(m => m.BaseUrl).Returns(_baseUrl);
_uut = _container.Instance;
}
The following fails with 0 calls, which makes sense since I believe it's looking at the Getter, not the Setter. So how do I assert that the Setter was called by the unit under test?
[Test]
public void BaseUrlSet()
{
//act
var _ = _uut.MakeRequest((InitialRequest) Arg.AnyObject);
//assert
_container.Assert<IRestService>(m => m.BaseUrl, Occurs.Once());
}
Per the documentation (located at JustMock Docs for anyone who isn't familiar but wishes to try assisting) it appears I should be using Mock.ArrangeSet(lambda), however I cannot seem to figure out how to get that syntax to work in relation to MockingContainer<T>.
If worse comes to worse, I can just NOT use MockingContainer<T>, but I'd prefer to not have to refactor my test suite just to accommodate one specific unit test.
Not that it's really relevant to the question, but in the off chance anyone needs it, here is a stub of ApiInteractionService
public ApiInteractionService(IRestService restService, IConfigService configService)
{
_restService = restService;
_restService.BaseUrl = configService.BaseUrl;
}
public string MakeRequest(InitialRequest initialRequest)
{
return _restService.Post(initialRequest);
}
Why not simply assert that BaseUrl has the correct value at the end of the test?
var baseUrl = _container.Get<IRestService>().BaseUrl;
Assert.AreEqual(baseUrl, _baseUrl);
As suggested in the comments, _container.Assert<IRestService>(m => m.BaseUrl == _baseUrl) will not work. MockingContainer<T>.Assert asserts an expectation, it's not just asserting truth like regular asserts. The correct syntax would have been:
_container.AssertSet<IRestService>(restService => restService.BaseUrl = _baseUrl, Occurs.Once());
but, oddly, there is no AssertSet method on the container.
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>();
I have the following test:
[Test]
public void VerifyThat_WhenInitializingTheLoggingInterceptionFacility_TheLoggingInterceptorIsAdded()
{
var kernel = new Mock<IKernel>(MockBehavior.Loose)
{
DefaultValue = DefaultValue.Mock
};
kernel.Setup(k => k.AddFacility<LoggingInterceptionFacility>())
.Returns(kernel.Object)
.Callback(() => ((IFacility)new LoggingInterceptionFacility()).Init(kernel.Object, Mock.Of<IConfiguration>()));
kernel.Setup(k => k.Register(It.IsAny<IRegistration[]>()))
.Returns(kernel.Object)
.Verifiable();
kernel.Object.AddFacility<LoggingInterceptionFacility>();
kernel.Verify(k => k.Register(It.Is<IRegistration[]>(r => r.Contains(Component.For<LoggingInterceptor>()))));
}
As you can see I am mocking the real behavior of the kernel by calling the facilitiy's Init(IKernel, IConfiguration) method which in turns calls the protected Init() method.
Here's how the protected Init() looks like:
protected override void Init()
{
Kernel.ProxyFactory.AddInterceptorSelector(new LoggingModelInterceptorsSelector());
Kernel.Register(Component.For<LoggingInterceptor>());
}
I expected that the verification would pass but it does not. If I verify that the Kernel.Register was called at all with It.IsAny<LoggingInterceptor>() the test passes.
What am I not matching right here? Is there a way to make this test pass?
It seems like you are testing way too much here. You are effectively reimplmenting a lot of Windsor's internals by piping calls from AddFacility to LoggingInterceptionFacility.Init.
All you really need to test is the fact that your facility calls Register on the kernel and assume that Windsor does the right thing. After all, it has unit tests of its own ;)
After doing that, the test becomes much more readable, which I consider the most important aspect.
[Test]
public void VerifyThat_WhenInitializingTheLoggingInterceptionFacility_TheLoggingInterceptorIsAdded()
{
var kernel = new Mock<IKernel>();
kernel.Setup(k => k.Register(It.IsAny<IRegistration[]>()))
.Returns(kernel.Object)
.Verifiable();
//Explicit interface implementation requires casting to the interface
((IFacility)new LoggingInterceptionFacility()).Init(kernel.Object, Mock.Of<IConfiguration>().Object);
//verify the type of registration here
kernel.Verify(k => k.Register(It.Is<IRegistration[]>(r => r[0] is ComponentRegistration<LoggingInterceptor>);
}
EDIT Calls to Component.For return different instances between setup and execution. I updated the code to reflect that and have the verification check the type of the component.
Can't figure out the syntax.
//class under test
public class CustomerRepository : ICustomerRepository{
public Customer Single(Expression<Func<Customer, bool>> query){
//call underlying repository
}
}
//test
var mock = new Mock<ICustomerRepository>();
mock.Object.Single(x=>x.Id == 1);
//now need to verify that it was called with certain expression, how?
mock.Verify(x=>x.Single(It.Is<Expression<Func<Customer, bool>>>(????)), Times.Once());
Please help.
Hmmm, you can verify that the lambda is being called by creating a mock for an interface that has a method matching the lambda parameters and verifying that:
public void Test()
{
var funcMock = new Mock<IFuncMock>();
Func<Customer, bool> func = (param) => funcMock.Object.Function(param);
var mock = new Mock<ICustomerRepository>();
mock.Object.Single(func);
funcMock.Verify(f => f.Function(It.IsAny<Customer>()));
}
public interface IFuncMock {
bool Function(Customer param);
}
The above might or might not work for you, depending on what Single method does with the Expression. If that expression gets parsed into SQL statement or gets passed onto Entity Framework or LINQ To SQL then it'd crash at runtime. If, however, it does a simple compilation of the expression, then you might get away with it.
The expression compilation that I spoke of would look something like this:
Func<Customer, bool> func = Expression.Lambda<Func<Customer, bool>>(expr, Expression.Parameter(typeof(Customer))).Compile();
EDIT If you simply want to verify that the method was called with a certain expression, you can match on expression instance.
public void Test()
{
Expression<Func<Customer, bool>> func = (param) => param.Id == 1
var mock = new Mock<ICustomerRepository>();
mock.Object.Single(func);
mock.Verify(cust=>cust.Single(func));
}