How can I to make a unit test check that a list of object not contains a duplicate element based on some properties.
Here is what I tried to do:
[Fact]
public void RecupererReferentielContactClient_CasNominal_ResultOk()
{
// Arange
var contactCoreService = Resolve<IContactCoreService>();
int clientId = 56605;
ICollection<Personne> listPersone = new List<Personne>();
// Act
WithUnitOfWork(() => listPersone = contactCoreService.RecupererReferentielDeContactClient(clientId));
// Assert
listPersone.ShouldSatisfyAllConditions(
() => listPersone.ShouldNotBeNull(),
() => listPersone.ShouldBeUnique());
}
How can I make my unit test using shouldly?
Group by all the properties you want to check, and then test if all the groups have exactly 1 item.
bool allUnique= listPersone
.GroupBy(p=> new {properties you want to check})
.All(g=>g.Count()==1);
Assert.True(allUnique)
actual.GroupBy(k => k.Id).ShouldAllBe(item => item.Count() == 1);
will show a non-unique item, if assert failed
Related
I am using Moq to mock Entity Framework Core's DbSet to return items in a test.
I got a test which gets the first item in the db set and checks its count. At the first time, I manage to get the object stored in the DbSet and the count is 1. At the second time, I get null in return but the count of the collection is still 1. When I debug and inspect, the collection inside the DbSet gives a message "Enumeration yielded no results"
[TestMethod]
public void MyTest()
{
var dbMock = GetDbContextMock();
Assert.AreEqual(1, dbMock.Object.Table2.Count()); //passes
Table2Model item1 = dbMock.Object.Table2.AsEnumerable().Where(x => x.DataCenter == "DataCenter").FirstOrDefault(); // item1 is an object
Assert.AreEqual(1, dbMock.Object.CurrentRunningServices.Count()); //passes
Table2Model item2 = dbMock.Object.Table2.AsEnumerable().Where(x => x.DataCenter == "DataCenter").FirstOrDefault(); //item2 is null
Assert.AreEqual(1, dbMock.Object.CurrentRunningServices.Count()); //passes
}
Why does the second time I get null instead of an object? It feels like some inner pointer somewhere didn't go back to the start of the collection of the DbSet.
Implementation:
private List<Table2Model> GetMockTable2List()
{
Table2Model item = new Table2Model();
item.DataCenter = "DataCenter";
return new List<Table2Model>() { item } ;
}
private Mock<MyDbContext> GetDbContextMock()
{
var realDal = new MyDbContext();
var dbContextMock = new Mock<MyDbContext>();
dbContextMock.SetupAllProperties();
dbContextMock.Object.Table1= realDal.Table1;
var table2List = GetMockTable2List().AsQueryable();
var table2DbSetMock = new Mock<DbSet<Table2Model>>();
table2DbSetMock.As<IQueryable<Table2Model>>().Setup(m => m.Provider).Returns(table2List.Provider);
table2DbSetMock.As<IQueryable<Table2Model>>().Setup(m => m.Expression).Returns(table2List.Expression);
table2DbSetMock.As<IQueryable<Table2Model>>().Setup(m => m.ElementType).Returns(table2List.ElementType);
table2DbSetMock.As<IQueryable<Table2Model>>().Setup(m => m.GetEnumerator()).Returns(table2List.GetEnumerator());
dbContextMock.Object.Table2 = table2DbSetMock.Object;
return dbContextMock;
}
The problem is with the line
table2DbSetMock.As<IQueryable<Table2Model>>().Setup(m => m.GetEnumerator()).Returns(table2List.GetEnumerator());
It returns the same enumerator every time. The way to fix it is to change the Returns value to a lambda:
table2DbSetMock.As<IQueryable<Table2Model>>().Setup(m => m.GetEnumerator()).Returns(() => table2List.GetEnumerator());
I have this test which verifies if I call the Query() in my reference.
[TestFixture]
public class When_retrieving_an_application_license
{
[Test]
public void available_licenses_should_be_counted()
{
// Arrange
var sut = new LicenseManager();
var mockILicenseRepository = new Mock<ILicenseRepository>();
sut.LicenseRepository = mockILicenseRepository.Object;
// Act
sut.GetLicenseCount(Guid.NewGuid(), Guid.NewGuid());
// Assert
mockIApplicationLicenseRepository.Verify(x => x.Query());
}
}
However, the GetLicenseCount(Guid.NewGuid(), Guid.NewGuid()) function looks like this:
public int GetLicenseCount(Guid cId, Guid appId)
=> LicenseRepository.Query()
.Count(al => al.CId == cId && al.AppId == appId
&& al.UserId == null
&& al.Expiry > DateTime.UtcNow);
Query() returns all in the repo to count which UserId's are in null.
Is it enough to say that the test is OK even if it only verifies the query() part of the linq?
How about the count?
If you are wanting to make sure the right count is being returned you will need to arrange your mocked ILicenseRepository to return the data you are expecting.
var mockILicenseRepository = new Mock<ILicenseRepository>();
mockILicenseRepository.Setup(x => x.Query()).Returns(new {CId = guid, AppId = guid2, Expiry = DateTime.Now.AddDays(1)};
You will also need to store the return value to assert against
var actualCount = sut.GetLicenseCount(Guid.NewGuid(), Guid.NewGuid());
Assert.AreEqual(expectedCount, actualCount);
However, if you are unit testing LINQ's Query method then I think you may want to restructure your production code because unit testing framework methods is unnecessary.
I want to test that a method adds a record to a DBSet under a certain condition:
public static void AddTriggeredInternalTransactions(IDataContext dc, ExternalTransaction transaction)
{
if (transaction [meets condition A])
dc.InternalTransactions.CreateInverseTransaction(transaction);
// do other stuff under other conditions
}
private static void CreateInverseTransaction(this IDbSet<InternalTransaction> transactions, ExternalTransaction from)
{
var internalTransaction = transactions.Create();
from.CopyToInternalTransaction(internalTransaction);
transactions.Add(internalTransaction);
}
Now, I already have tests for CopyToInternalTransaction(). I just need to call AddTriggeredInternalTransactions() and verify that [condition A] results in the new record being added).
I started with http://msdn.microsoft.com/en-us/data/dn314429.aspx, then used other Google and StackOverflow searches. Before tackling my "real" test, I'm trying to do a simple test just to verify whether a record has been added to a dataset, but I'm stuck on this. Can anyone point out my flaw(s)?
var internals = new Mock<DbSet<InternalTransaction>>();
var theData = new List<InternalTransaction>().AsQueryable();
internals.As<IQueryable<InternalTransaction>>().Setup(m => m.Provider).Returns(theData.Provider);
internals.As<IQueryable<InternalTransaction>>().Setup(m => m.Expression).Returns(theData.Expression);
internals.As<IQueryable<InternalTransaction>>().Setup(m => m.ElementType).Returns(theData.ElementType);
internals.As<IQueryable<InternalTransaction>>().Setup(m => m.GetEnumerator()).Returns(theData.GetEnumerator());
var mockDC = new Mock<IDataContext>();
mockDC.Setup(q => q.InternalTransactions).Returns(internals.Object);
mockDC.Setup(q => q.InternalTransactions.Create()).Returns(new InternalTransaction());
mockDC.Setup(q => q.InternalTransactions.Add(It.IsAny<InternalTransaction>()));
var it = mockDC.Object.InternalTransactions.Create();
it.Id = "123";
mockDC.Object.InternalTransactions.Add(it);
internals.Verify(e => e.Add(It.Is<InternalTransaction>(d => d.Id == "123")), Times.Once());
//or: Assert.Equal(1, mockDC.Object.InternalTransactions.Count());
This test fails with: Expected invocation on the mock once, but was 0 times: e => e.Add(It.Is(d => d.Id == "123")) No setups configured. No invocations performed.
The Assert statement, if used instead, fails with a NotImplementedException: "The member IQueryable.Provider has not been implemented on type DbSet~1Proxy_1 which inherits from DbSet1. Test doubles for DbSet1 must provide implementations of methods and properties that are used."
After comments by Adam and Stuart plus further experimentation, I was able to reduce my test case to the following working test case:
var internals = new Mock<DbSet<InternalTransaction>>();
var mockDC = new Mock<IDataContext>();
mockDC.Setup(q => q.InternalTransactions).Returns(internals.Object);
internals.Setup(q => q.Create()).Returns(new InternalTransaction());
var transaction = new ExternalTransaction { [set criteria for Condition A] };
SomeBusinessObject.AddTriggeredInternalTransactions(mockDC.Object, transaction);
// verify the Add method was executed exactly once
internals.Verify(e => e.Add(It.IsAny<InternalTransaction>()), Times.Once());
For one of my assignments I've had to make a method that will return the next item from a database using IRepository as a base. I'm using a TDD design cycle, and so far, this is what I have:
[TestMethod]
public void ShouldReturnNextExportRequest()
{
var requests = new List<ExportRequest>();
for (var i = 0; i < 100; i++)
{
var exportRequest = new Mock<ExportRequest>();
exportRequest.SetupGet(req => req.Id).Returns(i);
requests.Add(exportRequest.Object);
}
// Over-writing variables is bad
requests = requests.OrderBy(er => er.Id).ToList();
/**
* Mock the IRepository so that the Min() call returns the export request with the minimum Id
*/
var repo = new Mock<IRepository<ExportRequest>>();
repo.Setup(rep => rep.Min(It.IsAny<Expression<Func<ExportRequest, int>>>()))
.Returns<Expression<Func<ExportRequest, int>>>(expr => requests.Min(e => e.Id));
repo.Setup(rep => rep.Get(It.IsAny<int>())).Returns<int>(requests.ElementAt);
repo.Setup(rep => rep.Delete(It.IsAny<ExportRequest>()))
.Callback<ExportRequest>(req => Assert.IsTrue(requests.Remove(req), "Couldn't remove {0} from list", req.Id));
var exportRequestRepository = new ExportRequestRepository(repo.Object);
exportRequestRepository.GetNextRequest();
exportRequestRepository.GetNextRequest();
var third = exportRequestRepository.GetNextRequest();
var top = requests.First();
Assert.AreEqual(top.Id, third.Id, "Top element in list has id of {0}, but return from repository is {1}", top.Id, third.Id);
}
The GetNextRequest() method simply does this:
public ExportRequest GetNextRequest()
{
var top = _exportRequestRepository.Min(er => er.Id);
var element = _exportRequestRepository.Get(top);
_exportRequestRepository.Delete(element);
return element;
}
It all works perfectly fine, however the second element - with an id of 1 - is never removed from the list. I've worked this out to be down to the IEnumerable.Min implementation on List, as when it never seems to return an element with Id of 1 (determined by looking at the List in debug mode).
Am I missing something obvious?
NOTE:
I'm using a mocked IRepository from SharpRepository. Not that it makes a difference, as a Moq-ed interface has no inherent actions, but it's worth noting.
EDIT: test output.
Test Name: ShouldReturnNextExportRequest
Test FullName: ExportService.Tests.ExportRequestRepositorySpecification.ShouldReturnNextExportRequest
Test Source: c:\Users\dan.pantry\Desktop\RUMM\ExportService.Tests\ExportRequestRepositorySpecification.cs : line 17
Test Outcome: Failed
Test Duration: 0:00:00.211873
Result Message: Assert.AreEqual failed. Expected:<1>. Actual:<3>. Top element in list has id of 1, but return from repository is 3
Result StackTrace: at ExportService.Tests.ExportRequestRepositorySpecification.ShouldReturnNextExportRequest() in c:\Users\dan.pantry\Desktop\RUMM\ExportService.Tests\ExportRequestRepositorySpecification.cs:line 49
EDIT2: So I put a Callback on Get() like so:
repo.Setup(rep => rep.Get(It.IsAny<int>())).Returns<int>(requests.ElementAt)
.Callback<int>(req => Console.WriteLine("Retrieved {0}", req));
And now my output looks a bit like this:
Retrieved 0
Retrieved 1
Retrieved 1
EDIT3: Here is the origin of _exportRequestRepository in GetNextRequest() - In the test it's the mocked Repository and is injected into the constructor
public ExportRequestRepository(IRepository<ExportRequest> exportRequestRepository)
{
_exportRequestRepository = exportRequestRepository;
}
Issue solved.
The problem was that I was using ElementAt when I should have been using Find, and that I was calling First() before GetNextRequest() (get next request "pops" the elements from the underlying repository - will probably change that, though).
var repo = new Mock<IRepository<ExportRequest>>();
repo.Setup(rep => rep.Min(It.IsAny<Expression<Func<ExportRequest, int>>>()))
.Returns<Expression<Func<ExportRequest, int>>>(expr => requests.Min(e => e.Id));
repo.Setup(rep => rep.Get(It.IsAny<int>())).Returns<int>(i => requests.Find(er => er.Id == i));
repo.Setup(rep => rep.Delete(It.IsAny<ExportRequest>()))
.Callback<ExportRequest>(req => Assert.IsTrue(requests.Remove(req), "Couldn't remove {0} from list", req.Id));
var exportRequestRepository = new ExportRequestRepository(repo.Object);
Assert.AreEqual(0, exportRequestRepository.GetNextRequest().Id);
Assert.AreEqual(1, exportRequestRepository.GetNextRequest().Id);
var top = requests.First();
var third = exportRequestRepository.GetNextRequest();
Assert.AreEqual(top.Id, third.Id, "Top element in list has id of {0}, but return from repository is {1}", top.Id, third.Id);
Solved code is as above. As you can see, Get now uses requests.Find() rather than requests.ElementAt
I have the following sample test code
public Stage Test(Stage Stage)
{
var StartStage = StageRepository.Single(x => x.Order == 1);
var EndStage = StageRepository.Single(x => x.Order == 5);
var ErrorStage = StageRepository.Single(x => x.Name == "Error");
if (Stage == StartStage)
{
return EndStage;
}
else
{
return ErrorStage;
}
}
And I am trying to test it using the following unit test
[TestMethod]
public void XXXTest()
{
//// Arrange
var AutoMocker = new RhinoAutoMocker<StageService>(MockMode.AAA);
MockRepository mockRepository = new MockRepository();
var MockStageRepository = AutoMocker.Get<IRepository<Stage>>();
Stage StartStage = mockRepository.Stub<Stage>();
StartStage.Order = 1;
Stage EndStage = mockRepository.Stub<Stage>();
EndStage.Order = 5;
Stage ErrorStage = mockRepository.Stub<Stage>();
ErrorStage.Name = "Error";
System.Linq.Expressions.Expression<Func<Entities.Stage, bool>> StartParam = x => x.Order == 1;
MockStageRepository
.Stub(x => x.Single(Arg<System.Linq.Expressions.Expression<Func<Entities.Stage, bool>>>.Is.Equal(StartParam)))
.Return(StartStage);
System.Linq.Expressions.Expression<Func<Entities.Stage, bool>> EndParam = x => x.Order == 1;
MockStageRepository
.Stub(x => x.Single(Arg<System.Linq.Expressions.Expression<Func<Entities.Stage, bool>>>.Is.Equal(EndParam)))
.Return(EndStage);
System.Linq.Expressions.Expression<Func<Entities.Stage, bool>> ErrorParam = x => x.Order == 1;
MockStageRepository
.Stub(x => x.Single(Arg<System.Linq.Expressions.Expression<Func<Entities.Stage, bool>>>.Is.Equal(ErrorParam)))
.Return(ErrorStage);
StageService StageService = AutoMocker.ClassUnderTest;
//Act
var ReturnStage = StageService.Test(StartStage);
//Assert
Assert.AreEqual(ReturnStage, EndStage);
}
However this is not working as it is not returning anything when I call StageRepository.Single(). If I change the stub code to ignore the argument then it does return something but it will be the same object returned for each call to Single() which I don't want.
Is it possible to configure RhinoMocks in such a way as to return different objects from a stub depending on the lambda that is passed into it?
I think the root of your problem is that equality on the Expression<Func<T,U>> type is performed by reference rather than value. That means your telling Rhino Mocks to look for instances of expressions created in the test rather than the ones created in the code your testing.
Two possible approaches come to mind:
One would be to provide a way to pass the lambda expressions in to the Stage class from the test, so that when the argument checks happen they are working against the same instances.
Maybe something like:
internal void SetStartStage(Expression<Func<Entities.Stage,bool>> predicate)
{
...
}
The inverse of this would also work, i.e. provide the Expression objects as fields/properties that can be accessed by you're test, and then use those when setting up your mock:
internal Expression<Func<Entities.State,bool>> StartStagePredicate
{
get{ return x => x.Order == 1; }
}
Another option would be to use the Matches method on Args to see if the argument checks the Stage object state correctly. This would require creating some Stage objects in your test that would match the criteria:
var startStageTester = new Stage { Order = 1 };
MockStageRepository
.Stub(x => x.Single(Arg<System.Linq.Expressions.Expression<Func<Entities.Stage, bool>>>.Matches(y => y.Compile()(startStageTester)))
.Return(StartStage);
The call to Compile() is a little jarring, but since you're dealing with an Expression and not a straight-up lambda, you've got to compile it in order to evaluate it.
Now, if a Stage is something that is hard to create, then you may need to create a Mock/Stub of one (or use you're StartStage) and have it return 1 from the Order property (in the case of the StartStage anyway).
There are probably some others I'm not thinking of at the moment as well.
IF the linq condition is not important, I would propose to match it as any, something like this
repository.Stub(x => x.Find(Arg<System.Linq.Expressions.Expression<Func<Entity, bool>>>.Is.Anything)).Return(entitiesList.AsQueryable());
Hope this help.
Thanks for that. That worked a treat. The one thing that I was missing was the Compile method on an ExpressionTree. There is a small bug in your sample code (you use x twice). For completeness here is the working code.
MockStageRepository2
.Stub(x => x.Single(Arg<System.Linq.Expressions.Expression<Func<Entities.Stage, bool>>>.Matches(y => y.Compile()(StartStage2))))
.Return(StartStage2);