Testing Repository update or insert using Moq - moq

I have a method like this:
public int InsertOrUpdateCustomer(Customer customer)
{
var result = default(int);
try
{
using (var customerContext = new Customer())
{
var customerResult = customerContext.UpdateGraph(coupon, map => map.OwnedCollection(p => p.CustomerPoints));
couponsContext.SaveChanges();
result = customerResult.CustomerTypeID;
}
}
catch (Exception ex)
{
// Log the Exception
}
return result;
}
It creates an instance of CustomerContext, Saves, and returns the new CustomerID.
I am trying to use Moq for this and have this method where the test needs to check for a integer value being returned.
[TestMethod]
public void Inserting_A_Customer_Should_Return_A_IntegerValue(Customer customer)
{
var mock = new Mock<ICustomerRepository>();
int customerId = 1;
mock.Setup(c => c.InsertOrUpdateCustomer(customer)).Returns(new Customer() { Id = customerId });
}
That gives this error:
cannot convert from 'Entities.Commerce.Customer' to 'System.Func<int>'
I am also new to Moq.
What I would like to know from this question is, if one has a code like above, how does one proceed with writing Unit Tests.
It would be of great help if some pointers are given in getting to know that process.
Thanks in advance.

The error itself is because the method you are setting up is of this signature:
public int InsertOrUpdateCustomer(Customer customer)
Whereas your setup is trying to return a customer
mock.Setup(c => c.InsertOrUpdateCustomer(customer))
.Returns(new Customer() { Id = customerId });
Changing this to return a fake int such as .Returns(42); will avoid the error.
The not so good news is if the purpose of the test is Inserting_A_Customer_Should_Return_A_IntegerValue that you will be mocking the very thing you are trying to test (you would just be testing Moq).
What you need to do is Moq out your DbContext, which makes this line problematic, given its tight coupling:
using (var customerContext = new CustomerContext())
The suggestion here is to either allow the DbContext to be injected into the constructor of your class you are testing (or inject a factory interface which can create a DbContext).
You can then Mock the DbContext and the relevant IDbSets (Customers) as per this MSDN article here, which you can then inject into your class being tested, and test any logic / branching in your class.

Related

How to test the method passed to subscribe method of the PubSubEvent in the Wpf Prism library?

I have two ViewModels, MainWindowShellViewModel(shellVm) and MainWindowContentViewModel(contentVm). The shellVm publishes an event and the contentVm subscribes to it.
The shell VM looks something like the following. I have omitted many details.
// ctor
public MainWindowShellViewModel(IEventAggregator eventAggregator)
{
_EventAggregator = eventAggregator ?? throw new ArgumentNullException(nameof(IEventAggregator) + " service injected is null!!!");
_AppStartingClosingEventToken = _EventAggregator.GetEvent<AppStartingClosingEvent>();
}
private void MainWindowShellLoaded()
{
var payload = new AppStartingClosingEventData();
payload.Data = "MainWindowStarting";
_AppStartingClosingEventToken.Publish(payload);
}
The AppStartingClosingEvent is a no brainer type as follows.
public class AppStartingClosingEvent : PubSubEvent<AppStartingClosingEventData>
{ }
public class AppStartingClosingEventData
{
public string Data { get; set; }
}
And finally, the contentVm looks as follows.
public MainWindowContentViewModel(IEventAggregator eventAggregator)
{
_AppClosingEventToken.Subscribe(AppStartingClosing);
}
private void AppStartingClosing(AppStartingClosingEventData appStartingClosingEventData)
{
if (appStartingClosingEventData.Data == "MainWindowStarting")
LoadState(appStartingClosingEventData);
if (appStartingClosingEventData.Data == "MainWindowClosing")
SaveState(appStartingClosingEventData);
}
I want to test the that the method AppStartingClosing inside of contentVm is called with proper data. I am using Moq
I am running out of ideas. Please suggest. Tried the following but so far no success.
How do I test Prism event aggregator subscriptions, on the UIThread?
Using Moq to verify a Prism event subscription fails
Unit testing with Moq, Prism 6, and Event Aggregation
Moq Event Aggregator Is it possible
// Verifying a delegate was called with Moq
EDIT
Here is what I have tried.
// Arrange
var mockingKernel = new MoqMockingKernel();
var eventAggregatorMock = mockingKernel.GetMock<IEventAggregator>();
var eventBeingListenedTo = new AppStartingClosingEvent();
eventAggregatorMock.Setup(e => e.GetEvent<AppStartingClosingEvent>()).Returns(eventBeingListenedTo);
var vm = mockingKernel.Get<MainWindowContentViewModel>();
var evData = new AppStartingClosingEventData();
evData.Data = "MainWindowStarting";
// Act
eventBeingListenedTo.Publish(evData);
Now, what should I do? I am not even clear if I have approached correctly.
Now what should I do?
After eventBeingListenedTo.Publish(evData); look whether whatever effect SaveState should have is actually happening.
I am not even clear if I have approached correctly.
You do not want to test whether one method in a class is called by another method of that class.
So instead of trying to do
subjectUnderTest.DoStuff();
MagicallyVerifyThatThisGotCalled( () => subjectUnderTest.SomeEffect() );
you should do
var subjectUnderTest = new SubjectUnderTest( serviceMock.Object );
subjectUnderTest.DoStuff();
serviceMock.Verify( x => x.SomeEffectOnTheService(), Times.Once );
Assert.That( subjectUnderTest.SomePropertyThatsChanged, Is.EqualTo( newValue ) );
Whatever SubjectUnderTest does internally to achieve the desired effect, is not in the scope of the test. It's private to SubjectUnderTest, you don't care how it is done as long as it is done at all. When testing, look at the externally visible state of your subject under test, and what it does to its dependencies.

in API, create multiple controller constructor with one parameter

[Route("api/[controller]")]
public class DigitalDocumentController : Controller
{
private IDigitalDocumentService digitalDocumentService;
private IDatabaseInitializer databaseInitializer;
public DigitalDocumentController(IDigitalDocumentService digitalDocumentService)
{
this.digitalDocumentService = digitalDocumentService;
}
public DigitalDocumentController(IDatabaseInitializer databaseInitializer)
{
this.databaseInitializer = databaseInitializer;
}
i want two controller constructor in my project to Mock in xUnit Testing, but there was an error in my swagger interface {
"error": "Multiple constructors accepting all given argument types have been found in type 'i2ana.Web.Controllers.DigitalDocumentController'. There should only be one applicable constructor."
}
can anybody help me how i can do it ?
…
what i am try to do , is to test Uniquness of the Name Field in my database
My testing code:
[Fact]
public void AddNotUniqueName_ReturnsNotFoundObjectResult()
{
var digitalDocument = new DigitalDocument
{
Image = new byte[] { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 },
CreatedOn = DateTime.Today,
Id = 6,
Location = "temp",
Name = "Flower",
Tages = new List<Tag> { new Tag { Id = 1, Value = "Tag 1" }, new Tag { Id = 1, Value = "Tag 2" } }
};
// Arrange
var mockRepo = new Mock<IDatabaseInitializer>();
mockRepo.Setup(repo => repo.SeedAsync()).Returns(Task.FromResult(AddUniqueDigitalDocument(digitalDocument)));
var controller = new DigitalDocumentController(mockRepo.Object);
// Act
var result = controller.Add(digitalDocument);
// Assert
var viewResult = Assert.IsType<NotFoundObjectResult>(result);
var model = Assert.IsAssignableFrom<int>(viewResult.Value);
Assert.NotEqual(6, model);
}
the "AddUniqueDigitalDocument" returns 6 only to test that the new digitaldocumet is not the same id of my initialize data.
When using dependency injection, you should only have one constructor where all dependencies can be satisfied. Otherwise, how is the DI container to know which constructor to utilize? That's your issue here. Using the Microsoft.Extensions.DependencyInjection package, and since this is a controller you're injecting into, there's only one reasonable way to solve this: don't register one or the other of the services, IDigitalDocumentService or IDatatabaseInitializer. If only one is registered, the service collection will simply use the constructor it has a registered service for.
It's possible with a more featured DI container, you might be able to configure something to allow it choose the proper constructor. How to do that would be entirely dependent on the DI container you end up going with, though, so not much more can be said on the subject at this point. Just realize that the default container (Microsoft.Extensions.DependencyInjection) is intentionally simplistic, so if you needs are more complex, you should sub in a full DI container.
UPDATE
You should be doing integration testing with the test host and an in-memory database. The basic approach is:
public MyTests()
{
_server = new TestServer(new WebHostBuilder().UseStartup<TestStartup>());
_context = _server.Host.Services.GetRequiredService<MyContext>();
_client = _server.CreateClient();
}
In your app's Startup, create a virtual method:
public virtual void ConfigureDatabase(IServiceCollection services)
{
// normal database setup here, e.g.
services.AddDbContext<MyContext>(o =>
o.UseSqlServer(Configuration.GetConnectionString("Foo")));
}
Then, in ConfigureServices, replace your database setup with a call to this method.
Finally, in your test project, create a TestStartup class and override the ConfigureDatabase method:
public class TestStartup : Startup
{
public override void ConfigureDatabase(IServiceCollection services)
{
var databaseName = Guid.NewGuid().ToString();
services.AddDbContext<MyContext>(o =>
o.UseInMemoryDatabase(databaseName));
}
}
Now, in your tests you just make requests against the test client (which is just an HttpClient instance, so it works like any other HttpClient). You start by setting up your database with appropriate test data, and then ensure that the correct response is returned:
// Arrange
_context.Add(new DigitalDocument { Name = "Foo" });
await _context.SaveChanges();
// Act
// Submit a `DigitalDocument` with the same name via `_client`
// Assert
// Inspect the response body for some indication that it was considered invalid. Or you could simply assert that no new `DigitalDocument` was created by querying `_context` (or both)
This is admittedly a lot easier with an API, as with a web application, you're going to invariably need to do some HTML parsing. However, the docs and corresponding sample app help you with that.
Additionally, in actual practice, you'd want to use a test fixture to prevent having to bootstrap a test server for every test. Again, the docs have you covered there. One thing to note, though, is that once you switch to using a fixture, your database will then be persisted between tests. To segregate your test data, make sure that you call EnsureDeleted() on your context before each test. This can be easily done in the test class' constructor:
public class MyTests : IClassFixture<WebApplicationFactory<Startup>>
{
private readonly HttpClient _client;
private readonly MyContext _context;
public MyTests(WebApplicationFactory<Startup> factory)
{
factory = factory.WithWebHostBuilder(builder => builder.UseStartup<TestStartup>());
_client = factory.CreateClient();
_context = factory.Server.Host.Services.GetRequiredService<MyContext>();
_context.EnsureDeleted();
}
I don't even like this much bootstrapping code in my tests, though, so I usually inherit from a fixture class instead:
public class TestServerFixture : IClassFixture<WebApplicationFactory<Startup>>
{
protected readonly HttpClient _client;
protected readonly MyContext _context;
public TestServerFixture(WebApplicationFactory<Startup> factory)
{
factory = factory.WithWebHostBuilder(builder => builder.UseStartup<TestStartup>());
_client = factory.CreateClient();
_context = factory.Server.Host.Services.GetRequiredService<MyContext>();
_context.EnsureDeleted();
}
}
Then, for each test class:
public class MyTests : TestServerFixture
{
public MyTests(WebApplicationFactory<Startup> factory)
: base(factory)
{
}
This may seem like a lot, but most of it is one-time setup. Then, your tests will be much more accurate, more robust, and even easier in many ways.

Using autofixture in my data integration tests to create proxies

I'm trying to write a suite of database integration tests for my domain which uses Entity Framework. I would prefer to autofixture objects in some scenarios. My ideal syntax would be something like
[TestMethod]
public void AutofixtureMyEntityEntity()
{
var fixture = new Fixture();
fixture.Customize<MyEntity>(
c => c.FromFactory<MyDbContext>(ctx => ctx.Set<MyEntity>().Create()));
using (var context = new MyDbContext())
{
fixture.Inject(context);
var entity = fixture.CreateAnonymous<MyEntity>();
context.Set<MyEntity>().Add(entity);
context.SaveChanges();
}
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void AutoFixtureMyEntityEntityWithoutInjection()
{
var fixture = new Fixture();
fixture.Customize<MyEntity>(
c => c.FromFactory<MyDbContext>(ctx => ctx.Set<MyEntity>().Create()));
using (var context = new MyDbContext())
{
var entity = fixture.CreateAnonymous<MyEntity>();
context.Set<MyEntity>().Add(entity);
context.SaveChanges();
}
}
Obviously, that isn't working since CreateAnonymous() isn't expecting the input parameter for the factory. I can only assume that i have a flawed understanding of what FromFactory() provides. Although the comment reads,
/// Specifies that a specimen should be created in a particular way, using a single input
/// parameter for the factory.
After reading ploehs blog, I'm slightly more confused on how these pieces interact with each other.
The instance of MyDbContext during factory invocation is not the instance I passed to Inject()
Would something like this work?
var fixture = new Fixture();
fixture.Customize<MyEntity>(c => c
.FromFactory<MyDbContext, MyEntity>(ctx => ctx.Set<MyEntity>.Create()));
using (var context = new MyDbContext())
{
fixture.Inject(context);
var item = fixture.CreateAnonymous<MyEntity>();
context.Set<MyEntity>().Add(item);
context.SaveChanges();
}
Disclaimer: I haven't tried to compile this...
FWIW, if you were using xUnit.net with AutoFixture, you could reduce the test to something like:
[Theory, MyAutoData]
public void TheTest([Frozen]MyDbContext context, MyEntity item)
{
context.Set<MyEntity>().Add(item);
context.SaveChanges();
}

How to setup Moq to execute some methods of a Moq

I have a test where I pass in an object like so:
var repo = new ActualRepo();
var sut = new Sut(repo);
In my test, Repo has one method that I need to actually execute, whilst another method I want to mock out and not execute.
So for example, take this pseudocode:
var repo = new Mock<IRepo>();
repo.Setup(m => m.MethodIWantToCall()).WillBeExecuted();
repo.Setup(m => m.MethodIWantToMock()).Returns(false);
Using Moq, is this possible and how can it be done?
EDIT:
I've used TypeMock in the past and you can do something like.
Isolator.When(() => repo.MethodToIgnore()).WillBeIgnored();
Isolator.When(() => repo.MethodToActuallyRun()).WillBeExecuted();
Not too sure from the question if this is useful but it is possible to partially mock an object if the method that you want to mock is virtual.
public class Foo {
public string GetLive() {
return "Hello";
}
public virtual string GetMock() {
return "Hello";
}
}
public class Snafu {
private Foo _foo;
public Snafu(Foo foo) {
_foo = foo;
}
public string GetMessage() {
return string.Format("{0} {1}", _foo.GetLive(), _foo.GetMock());
}
}
[TestMethod]
public void NotMocked() {
var snafu = new Snafu(new Foo());
Assert.AreEqual("Hello Hello", snafu.GetMessage());
}
[TestMethod]
public void Mocked() {
var mockFoo = new Mock<Foo>();
mockFoo.Setup(mk => mk.GetMock()).Returns("World");
var snafu = new Snafu(mockFoo.Object);
Assert.AreEqual("Hello World", snafu.GetMessage());
}
You can't do this with Moq if you use the same object unless one of the method is virtual and you are basing your mock on a type rather than an interface.
That's because when you are passing a mock object based on an interface, you aren't passing a real object so it does not have access to the real methods of the object.
You are passing a dynamic proxy which will respond to methods it has been setup to respond to.
I believe TypeMock rewrites the assemblies at runtime to achieve this, something Moq definitively doesn't do.
If you want to achieve similar results with Moq:
You could mock both methods
You would have to extract both methods to different dependencies so as to mock one dependency and not the other.
You could have the method you need mocked be virtual, which would be the solution I would prefer.
EDIT : I edited my answer for correctness after reading AlanT's answer.

Entity Framework telling me an object is attached when it isn't - why?

I have an object I want to update in the database. I'm new to EF but have done a fair bit of reading. Clearly my approach is wrong, but I don't understand why. FYI the Context referenced throughout is an ObjectContext which is newly instantiated as this code begins and is disposed immediately after. Here is my Update method - the View is the object I want to update in the database and it has 4 ICollection properties whose changes I also wish to save to the database:
public void Update(View view)
{
var original = Read(view.Username, view.ViewId);
original.ViewName = view.ViewName;
ProcessChanges<CostCentre, short>(Context.CostCentres, original.CostCentres, view.CostCentres, "iFinanceEntities.CostCentres", "CostCentreId");
ProcessChanges<LedgerGroup, byte>(Context.LedgerGroups, original.LedgerGroups, view.LedgerGroups, "iFinanceEntities.LedgerGroups", "LedgerGroupId");
ProcessChanges<Division, byte>(Context.Divisions, original.Divisions, view.Divisions, "iFinanceEntities.Divisions", "DivisionId");
ProcessChanges<AnalysisCode, short>(Context.AnalysisCodes, original.AnalysisCodes, view.AnalysisCodes, "iFinanceEntities.AnalysisCodes", "AnalysisCodeId");
int test = Context.SaveChanges();
}
First I get the original from the database because I want to compare its collections with the new set of collections. This should ensure the correct sub-objects are added and removed. I compare each collection in turn using this ProcessChanges method:
private void ProcessChanges<TEntity, TKey>(ObjectSet<TEntity> contextObjects, ICollection<TEntity> originalCollection, ICollection<TEntity> changedCollection, string entitySetName, string pkColumnName)
where TEntity : class, ILookupEntity<TKey>
{
List<TKey> toAdd = changedCollection
.Select(c => c.LookupKey)
.Except(originalCollection.Select(o => o.LookupKey))
.ToList();
List<TKey> toRemove = originalCollection
.Select(o => o.LookupKey)
.Except(changedCollection.Select(c => c.LookupKey))
.ToList();
toAdd.ForEach(a =>
{
var o = changedCollection.Single(c => c.LookupKey.Equals(a));
AttachToOrGet<TEntity, TKey>(entitySetName, pkColumnName, ref o);
originalCollection.Add(o);
});
toRemove.ForEach(r =>
{
var o = originalCollection.Single(c => c.LookupKey.Equals(r));
originalCollection.Remove(o);
});
}
This compares the new collection to the old one and works out which objects to add and which to remove. Note that the collections all contain objects which implement ILookupEntity.
My problems occur on the line where I call AttachToOrGet. This method I got from elsewhere on stackoverflow. I'm using this because I was often getting a message saying that "An object with the same key already exists in the ObjectStateManager" when attaching a new subobject. Hopefully you'll understand my confusion around this when I post the code of this method below:
public void AttachToOrGet<TEntity, TKey>(string entitySetName, string pkColumnName, ref TEntity entity)
where TEntity : class, ILookupEntity<TKey>
{
ObjectStateEntry entry;
// Track whether we need to perform an attach
bool attach = false;
if (Context.ObjectStateManager.TryGetObjectStateEntry(new EntityKey(entitySetName, pkColumnName, entity.LookupKey), out entry))
//if (Context.ObjectStateManager.TryGetObjectStateEntry(Context.CreateEntityKey(entitySetName, entity), out entry))
{
// Re-attach if necessary
attach = entry.State == EntityState.Detached;
// Get the discovered entity to the ref
entity = (TEntity)entry.Entity;
}
else
{
// Attach for the first time
attach = true;
}
if (attach)
Context.AttachTo(entitySetName, entity);
}
Basically this is saying if the entity is not already attached then attach it. But my code is returning false on the Context.ObjectStateManager.TryGetObjectStateEntry line, but throwing an exception on the final line with the message "An object with the same key already exists in the ObjectStateManager". To me this is paradoxical.
As far as I'm concerned I'm trying to achieve something very simple. Something it would take 20 minutes to write a stored procedure for. A simple database update. Frankly I don't care what is attached and what isn't because I don't wish to track changes or create proxies or lazy load or do anything else EF offers me. I just want to take a very simple object and update the database using a minimal number of trips between servers. How is this so complicated? Please someone help me - I've spent a whole day on this!
Update
Here's my ILookupEntity class:
public interface ILookupEntity<TKey>
{
TKey LookupKey { get; }
string DisplayText { get; }
}
Here's how it is implemented in CostCentre:
public partial class CostCentre : IFinancialCode, ILookupEntity<short>
{
#region IFinancialCode Members
public short ID { get { return CostCentreId; } }
public string DisplayText { get { return string.Format("{0} - {1}", Code, Description); } }
#endregion
#region ILookupEntity Members
public short LookupKey
{
get { return ID; }
}
#endregion ILookupEntity Members
}
Well, I've worked through this and found a solution, but I can't say I understand it. The crucial ingredient came when I was performing a check after the comment by #Slauma. I wanted to check I was using the correct entity set name etc so I included the following lines near the top of my AttachToOrGet method:
var key = new EntityKey(entitySetName, pkColumnName, entity.LookupKey);
object temp;
if (!Context.TryGetObjectByKey(key, out temp))
throw new Exception(string.Format("No entity was found in {0} with key {1}", entitySetName, entity.LookupKey));
Bizarrely this alone resolved the problem. For some reason, once I'd called the TryGetObjectByKey then the ObjectStateManager.TryGetObjectStateEntry call actually started locating the attached entity. Miraculous. I'd love it if anyone can explain this.
By the way, I also needed to include the following code, but that's just because in my case the modelled entities are located in a separate assembly from the context itself.
Assembly assembly = typeof(CostCentre).Assembly;
Context.MetadataWorkspace.LoadFromAssembly(assembly);

Categories

Resources