I have a simple class that sets a field in the constructor, and the matching property is read-only.
public class COMAssembly : ICOMAssembly
{
private List<string> properties = new List<string>();
public List<string> Properties
{
get { return properties; }
}
...
}
I have these test classes using MSpec and Moq:
using Machine.Specifications;
using Moq;
using System.Collections.Generic;
using It = Machine.Specifications.It;
public class MSPEC_With_a_COM_Assembly
{
protected static Mock<ICOMAssembly> _mockCOMAssembly;
protected static List<string> _listOfStrings;
Establish context = () =>
{
_mockCOMAssembly = new Mock<ICOMAssembly>(MockBehavior.Loose);
_mockCOMAssembly.DefaultValue = DefaultValue.Mock;
_mockCOMAssembly.SetupAllProperties();
_mockCOMAssembly.SetupProperty(m => m.Properties, new List<string>() { "Prop1", "Prop2" });
};
}
[Subject(typeof(MSPEC_With_a_COM_Assembly), "With a COM Assembly")]
public class When_asking_for_a_list_of_properties_and_assembly_has_properties : MSPEC_With_a_COM_Assembly
{
Because of = () =>
{
_listOfStrings = _mockCOMAssembly.Object.Properties;
};
It Should_return_a_list_with_values = () =>
{
//TODO: Verify that the Count property of _listOfStrings/_mockCOMAssembly.Object.Properties is greater than zero.
};
}
I've reviewed many forums, Moq tutorials, etc. and can't find an answer to how to do this using only Moq. I do not want to use NUnit. I have other tests that pass that verify that _listOfStrings is not null and the get on the property works fine. I'm new to practicing MSpec/Moq/Unit Testing, though I've read a lot on the topics so far. Any help is appreciated!
Related
I have the code below which I would like to test, but I'm not sure whether it is possible or not.
I have EF repositories and they are put together to a class as public properties. I don't know exactly whether it is bad solution or not, but it is easier to manage the code and its dependencies. Only the testability is still a question.
Purpose of my test is injecting data via
administrationRepository.ModuleScreen.GetAll()
method and catch the result. I know that it can be tested once it is deployed, but I want the tests in build time in order to have as fast feedback as possible.
I went through questions and answers here, but I cannot find answers. In my code I got to the point where the property is set up, but when I call the administrationRepoMock.Object.ModuleScreen.GetAll() ReSharper offers only the methods coming from Entitiy Framework and not the Moq related functions.
It is possible what I want? If so, how? Is my design suitable for this? If not can you give me articles, urls where I can see examples?
Repository:
public interface IModuleScreen
{
IEnumerable<DomainModel.Administration.ModuleScreen> GetAll();
}
public interface IAdministrationRepository
{
IModuleScreen ModuleScreen { get; }
}
public partial class AdministrationRepository : IAdministrationRepository
{
public virtual IModuleScreen ModuleScreen { get; private set; }
public AdministrationRepository( IModuleScreen moduleScreen )
{
this.ModuleScreen = moduleScreen;
}
}
Application:
public partial class DigitalLibraryApplication : IDigitalLibraryApplication
{
private IAdministrationRepository _administrationRepository;
private IMapper.IMapper.IMapper _mapper;
private IDiLibApplicationHelper _dilibApplicationHelper;
#region Ctor
public DigitalLibraryApplication( IAdministrationRepository administrationRepository, IMapper.IMapper.IMapper mapper, IDiLibApplicationHelper diLibApplicationHelper)
{
_administrationRepository = administrationRepository;
_mapper = mapper;
_dilibApplicationHelper = diLibApplicationHelper;
}
#endregion
public IEnumerable<ModuleScreenContract> GetModuleScreens()
{
//inject data here
IEnumerable<ModuleScreen> result = _administrationRepository.ModuleScreen.GetAll();
List<ModuleScreenContract> mappedResult = _mapper.MapModuleScreenToModuleScreenContracts(result);
return mappedResult;
}
}
Test code:
[Test]
public void ItCalls_ModuleRepository_Get_Method()
{
List<SayusiAndo.DiLib.DomainModel.Administration.ModuleScreen> queryResult = new List<SayusiAndo.DiLib.DomainModel.Administration.ModuleScreen>()
{
new DomainModel.Administration.ModuleScreen()
{
Id = 100,
},
};
var moduleScreenMock = new Mock<IModuleScreen>();
moduleScreenMock.Setup(c => c.GetAll()).Returns(queryResult);
administrationRepoMock.SetupProperty(c => c.ModuleScreen, moduleScreenMock.Object);
var mapperMock = new Mock<IMapper.IMapper.IMapper>();
var dilibApplicationHerlperMock = new Mock<IDiLibApplicationHelper>();
IDigitalLibraryApplication app = new DigitalLibraryApplication( administrationRepoMock.Object, mapperMock.Object, dilibApplicationHerlperMock.Object );
app.GetModules();
//issue is here
administrationRepoMock.Object.ModuleScreen.GetAll() //???
}
Here is a refactoring of your test that passes when run. You can update the pass criteria to suit you definition of a successful test.
[Test]
public void ItCalls_ModuleRepository_Get_Method() {
// Arrange
List<ModuleScreen> queryResult = new List<ModuleScreen>()
{
new ModuleScreen()
{
Id = 100,
},
};
//Building mapped result from query to compare results later
List<ModuleScreenContract> expectedMappedResult = queryResult
.Select(m => new ModuleScreenContract { Id = m.Id })
.ToList();
var moduleScreenMock = new Mock<IModuleScreen>();
moduleScreenMock
.Setup(c => c.GetAll())
.Returns(queryResult)
.Verifiable();
var administrationRepoMock = new Mock<IAdministrationRepository>();
administrationRepoMock
.Setup(c => c.ModuleScreen)
.Returns(moduleScreenMock.Object)
.Verifiable();
var mapperMock = new Mock<IMapper>();
mapperMock.Setup(c => c.MapModuleScreenToModuleScreenContracts(queryResult))
.Returns(expectedMappedResult)
.Verifiable();
//NOTE: Not seeing this guy doing anything. What's its purpose
var dilibApplicationHerlperMock = new Mock<IDiLibApplicationHelper>();
IDigitalLibraryApplication app = new DigitalLibraryApplication(administrationRepoMock.Object, mapperMock.Object, dilibApplicationHerlperMock.Object);
//Act (Call the method under test)
var actualMappedResult = app.GetModuleScreens();
//Assert
//Verify that configured methods were actually called. If not, test will fail.
moduleScreenMock.Verify();
mapperMock.Verify();
administrationRepoMock.Verify();
//there should actually be a result.
Assert.IsNotNull(actualMappedResult);
//with items
CollectionAssert.AllItemsAreNotNull(actualMappedResult.ToList());
//There lengths should be equal
Assert.AreEqual(queryResult.Count, actualMappedResult.Count());
//And there should be a mapped object with the same id (Assumption)
var expected = queryResult.First().Id;
var actual = actualMappedResult.First().Id;
Assert.AreEqual(expected, actual);
}
I am new to testing and have never used MSpec. I looked at tutorials and the only examples is "lite", like 1 + 1 should be 2. I need to test this real method and I don't know where to start.
public ILineItem CreateLineItem(BaseVariationContent sku, int quantityToAdd)
{
var price = sku.GetDefaultPrice();
var parent = sku.GetParentProducts().FirstOrDefault() != null ? _contentLoader.Get<ProductContent>(sku.GetParentProducts().FirstOrDefault()).Code : string.Empty;
return new LineItem
{
Code = sku.Code,
DisplayName = sku.DisplayName,
Description = sku.Description,
Quantity = quantityToAdd,
PlacedPrice = price.UnitPrice.Amount,
ListPrice = price.UnitPrice.Amount,
Created = DateAndTime.Now,
MaxQuantity = sku.MaxQuantity ?? 100,
MinQuantity = sku.MinQuantity ?? 1,
InventoryStatus = sku.TrackInventory ? (int)InventoryStatus.Enabled : (int)InventoryStatus.Disabled,
WarehouseCode = string.Empty, // TODO: Add warehouse id
ParentCatalogEntryId = parent,
};
}
BaseVariationContent is just a class with a lot of properties and that has an extension.
The MSpec github repo has a pretty nice README that explains the basic syntax components of an MSpec test class and test case.
https://github.com/machine/machine.specifications#machinespecifications
I won't fill in the details of your test, but I will show you the important parts to setup an mspec test.
[Subject("Line Item")]
public class When_creating_a_basic_line_item_from_generic_sku()
{
Establish context = () =>
{
// you would use this if the Subject's constructor
// required more complicated setup, mocks, etc.
}
Because of = () => Subject.CreateLineItem(Sku, Quantity);
It should_be_in_some_state = () => Item.InventoryStatus.ShouldEqual(InventoryStatus.Enabled);
private static Whatever Subject = new Whatever();
private static BaseVariationContent Sku = new GenericSku();
private static int Quantity = 1;
private static ILineItem Item;
}
You'll want to run these tests, so use the command-line tool
https://github.com/machine/machine.specifications#command-line-reference
or one of the integrations
https://github.com/machine/machine.specifications#resharper-integration
Let me navigate to you with a real implementation.
Let's assume you have a service called SiteService and it returns the current siteId (you have multiple siteIds for your application).
you want to write a test case, when requesting the current site it should return the site id definition in configuration.
you will need to create a test class (standard class file), let's give a meaningful name like "SiteServiceSpec.cs"
Next, you will need to mock the ISiteConfiguration so that it can get the site id from the SiteConfiguration
public abstract class SiteServiceContext : WithFakes
{
Establish context = () =>
{
var siteConfiguration = An<ISiteConfiguration>();
siteConfiguration.WhenToldTo(x => x.Id)
.Return(CurrentSiteId);
Repository = An<IRepository<WebSite.Domain.Site.Site>>();
SUT = new SiteService(siteConfiguration, Repository);
};
protected const short CurrentSiteId = 1;
protected static SiteService SUT;
protected static IRepository<WebSite.Domain.Site.Site> Repository;
}
Now, here comes the example of the test class.
[Subject(typeof(SiteService))]
public class When_requesting_current_site : SiteServiceContext
{
It should_return_site_with_id_defined_in_configuration = () =>
Result.Id.ShouldEqual(CurrentSiteId);
Establish context = () =>
{
var site = An<WebSite.Domain.Site.Site>();
site.WhenToldTo(x => x.Id)
.Return(CurrentSiteId);
Repository.WhenToldTo(x => x.GetById(CurrentSiteId))
.Return(site);
};
Because of = () =>
Result = SUT.GetCurrentSite();
static WebSite.Domain.Site.Site Result;
}
I hope it will help you to get an idea of how it works. Besides, follow the structure provided by #anthony-mastrean
In Fluent Assertions when comparing objects with DateTime properties there are sometimes a slight mismatch in the milliseconds and the comparison fail. The way we get around it is to set the comparison option like so:
actual.ShouldBeEquivalentTo(expected,
options =>
options.Using<DateTime>(ctx => ctx.Subject.Should().BeCloseTo(ctx.Expectation))
.WhenTypeIs<DateTime>());
Is there a way to set this up once and have it always apply instead of having to specify it every time we call ShouldBeEquivalentTo?
Update1:
Tried the following approach but it doesn't seem to work, test fails on 1 millisecond difference. The new default does not seem to get called by the factory.
using System;
using FluentAssertions;
using FluentAssertions.Equivalency;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace UnitTestProject1
{
class Test
{
public DateTime TestDateTime { get; set; }
}
[TestClass]
public class UnitTest1
{
[TestMethod]
public void SettingFluentAssertionDefault()
{
// arrange
var defaultAssertionOptions = EquivalencyAssertionOptions<DateTime>.Default;
EquivalencyAssertionOptions<DateTime>.Default = () =>
{
var config = defaultAssertionOptions();
config.Using<DateTime>(ctx => ctx.Subject.Should().BeCloseTo(ctx.Expectation)).WhenTypeIs<DateTime>();
return config;
};
var testDateTime = DateTime.Now;
var expected = new Test {TestDateTime = testDateTime};
// act
var actual = new Test {TestDateTime = testDateTime.AddMilliseconds(1)};
// assert
actual.ShouldBeEquivalentTo(expected);
}
}
}
Now this can be done with the AssertionOptions static class. To use a simple example:
[TestInitialize]
public void TestInit() {
AssertionOptions.AssertEquivalencyUsing(options => options.ExcludingMissingMembers());
}
Or as in the example above:
AssertionOptions.AssertEquivalencyUsing(options =>
options.Using<DateTime>(ctx => ctx.Subject.Should().BeCloseTo(ctx.Expectation)).WhenTypeIs<DateTime>()
);
Actually, you can. The default configuration factory is exposed by the static property EquivalencyAssertionOptions<Test>.Default. You can easily assign an alternative configuration for a particular data type, or extend the default configuration with additional behavior. Something like:
var defaultAssertionOptions = EquivalencyAssertionOptions<Test>.Default;
EquivalencyAssertionOptions<Test>.Default = () =>
{
var config = defaultAssertionOptions();
config.Using<DateTime>(ctx => ctx.Subject.Should().BeCloseTo(ctx.Expectation)).WhenTypeIs<DateTime>();
return config;
};
If you want you can get the current default and tuck that away in some variable that you use from your factory method.
I am afraid the closest thing you can come to, is providing new methods
public static void ShouldBeEquivalentToDef<T>(this T subject, object expectation, string reason = "",
params object[] reasonArgs)
{
ShouldBeEquivalentToDef(subject, expectation, config => config, reason, reasonArgs);
}
public static void ShouldBeEquivalentToDef<T>(this T subject, object expectation,
Func<EquivalencyAssertionOptions<T>, EquivalencyAssertionOptions<T>> config, string reason = "", params object[] reasonArgs)
{
var context = new EquivalencyValidationContext
{
Subject = subject,
Expectation = expectation,
CompileTimeType = typeof (T),
Reason = reason,
ReasonArgs = reasonArgs
};
var defConstructedOptions = config(EquivalencyAssertionOptions<T>.Default());
defConstructedOptions.Using<DateTime>(ctx => ctx.Subject.Should().BeCloseTo(ctx.Expectation))
.WhenTypeIs<DateTime>()
new EquivalencyValidator(defConstructedOptions).AssertEquality(context);
}
Is there a way to setup and verify a method call that use an Expression with Moq?
The first attempt is the one I would like to get it to work, while the second one is a "patch" to let the Assert part works (with the verify part still failing)
string goodUrl = "good-product-url";
[Setup]
public void SetUp()
{
productsQuery.Setup(x => x.GetByFilter(m=>m.Url== goodUrl).Returns(new Product() { Title = "Good product", ... });
}
[Test]
public void MyTest()
{
var controller = GetController();
var result = ((ViewResult)controller.Detail(goodUrl)).Model as ProductViewModel;
Assert.AreEqual("Good product", result.Title);
productsQuery.Verify(x => x.GetByFilter(t => t.Url == goodUrl), Times.Once());
}
Thet test fail at the Assert and throw a null reference exception, because the method GetByFilter is never called.
If instead I use this
[Setup]
public void SetUp()
{
productsQuery.Setup(x => x.GetByFilter(It.IsAny<Expression<Func<Product, bool>>>())).Returns(new Product() { Title = "Good product", ... });
}
The test pass the Assert part, but this time is the Verify that fail saying that it is never called.
Is there a way to setup a method call with a specific expression instead of using a generic It.IsAny<>()?
Update
I tried also the suggestion by Ufuk Hacıoğulları in the comments and created the following
Expression<Func<Product, bool>> goodUrlExpression = x => x.UrlRewrite == "GoodUrl";
[Setup]
public void SetUp()
{
productsQuery.Setup(x => x.GetByFilter(goodUrlExpression)).Returns(new Product() { Title = "Good product", ... });
}
[Test]
public void MyTest()
{
...
productsQuery.Verify(x => x.GetByFilter(goodUrlExpression), Times.Once());
}
But I get a null reference exception, as in the first attempt.
The code in my controller is as follow
public ActionResult Detail(string urlRewrite)
{
//Here, during tests, I get the null reference exception
var entity = productQueries.GetByFilter(x => x.UrlRewrite == urlRewrite);
var model = new ProductDetailViewModel() { UrlRewrite = entity.UrlRewrite, Culture = entity.Culture, Title = entity.Title };
return View(model);
}
The following code demonstrates how to test in such scenarios. The general idea is that you execute the passed in query against a "real" data. That way, you don't even need "Verify", as if the query is not right, it will not find the data.
Modify to suit your needs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Moq;
using NUnit.Framework;
namespace StackOverflowExample.Moq
{
public class Product
{
public string UrlRewrite { get; set; }
public string Title { get; set; }
}
public interface IProductQuery
{
Product GetByFilter(Expression<Func<Product, bool>> filter);
}
public class Controller
{
private readonly IProductQuery _queryProvider;
public Controller(IProductQuery queryProvider)
{
_queryProvider = queryProvider;
}
public Product GetProductByUrl(string urlRewrite)
{
return _queryProvider.GetByFilter(x => x.UrlRewrite == urlRewrite);
}
}
[TestFixture]
public class ExpressionMatching
{
[Test]
public void MatchTest()
{
//arrange
const string GOODURL = "goodurl";
var goodProduct = new Product {UrlRewrite = GOODURL};
var products = new List<Product>
{
goodProduct
};
var qp = new Mock<IProductQuery>();
qp.Setup(q => q.GetByFilter(It.IsAny<Expression<Func<Product, bool>>>()))
.Returns<Expression<Func<Product, bool>>>(q =>
{
var query = q.Compile();
return products.First(query);
});
var testController = new Controller(qp.Object);
//act
var foundProduct = testController.GetProductByUrl(GOODURL);
//assert
Assert.AreSame(foundProduct, goodProduct);
}
}
}
I am trying to experiment with RhinoMocks, where I have to say I am a newbie and probably I don't get some obvious thing here. What I'm doing is something like :
[TestMethod]
public void SaveResponsibleUserFromChangeset()
{
var action = mocks.StrictMock<GenomeAction>();
var changeset = new ActionChangeset();
changeset.ResponsibleUser = new ChangeableProperty<UserIdentity>("Administrator") {IsChanged = true};
changeset.MarkAll(true);
using(mocks.Record())
{
Expect.Call(action.ResponsibleUser).SetPropertyAndIgnoreArgument();
}
using(mocks.Playback())
{
var persistor = new ActionPersistor(new MockIdentityResolver());
persistor.SaveActionChanges(changeset, action);
}
action.VerifyAllExpectations();
}
private class MockIdentityResolver : IIdentityResolver
{
public GenomeUser GetUser(UserIdentity identity)
{
var user = mocks.DynamicMock<GenomeUser>();
user.Username = identity.Username;
return user;
}
}
The intention is to have a very simple test which checks whether the SaveActionChanges method sets the ResponsibleUser property. As a part of this, it needs to resolve the user identity using the resolver, for which I have provided a mock implementation. Unfortunately, it seems I can't just return back another mock within the Playback mode, because it says (on the closing bracket of the second using) that The action is invalid when the object (of type GenomeUser) is in record state.
Any ideas of what is causing the trouble and how to overcome it ?
I think you need to create you new MockIdentityResolver() outside the mocks.Playback().
[TestMethod]
public void SaveResponsibleUserFromChangeset()
{
var action = mocks.StrictMock<GenomeAction>();
var changeset = new ActionChangeset();
var identityResolver;
changeset.ResponsibleUser = new ChangeableProperty<UserIdentity>("Administrator") {IsChanged = true};
changeset.MarkAll(true);
using(mocks.Record())
{
Expect.Call(action.ResponsibleUser).SetPropertyAndIgnoreArgument();
identityResolver = new MockIdentityResolver()
}
using(mocks.Playback())
{
var persistor = new ActionPersistor(identityResolver);
persistor.SaveActionChanges(changeset, action);
}
action.VerifyAllExpectations();
}
private class MockIdentityResolver : IIdentityResolver
{
public GenomeUser GetUser(UserIdentity identity)
{
var user = mocks.DynamicMock<GenomeUser>();
user.Username = identity.Username;
return user;
}
}
you should look at using the AAA syntax, it seems to be generally accepted that it's a clearer way of using stuff.