I want to create "many" instances of foo :
var fixture = new Fixture();
var expectedFoos = fixture.CreateMany<Foo>();
The problem is, Foo is an Entity Framework entity, with relations that I don't want to create. If I needed only one instance, I could do that :
var fixture = new Fixture();
var expectedFoo = fixture.Build<Foo>()
.Without(foo => foo.Relation1);
.Without(foo => foo.Relation2);
But how can I easily create multiple instances satisfying this condition ? I've read about specimen builders but it seems really overkill here.
I'm looking for something as simple as that (doesn't compile because BuildMany doesn't exist) :
var fixture = new Fixture();
var expectedFoos = fixture.BuildMany<Foo>()
.Without(foo => foo.Relation1);
.Without(foo => foo.Relation2);
That's what Customize is for:
var fixture = new Fixture();
fixture.Customize<Foo>(o => o
.Without(foo => foo.Relation1)
.Without(foo => foo.Relation2));
var expectedFoos = fixture.CreateMany<Foo>();
Using Customize is definitely the right answer. However, just for the sake of documentation, Build will work too:
var expectedFoos = fixture.Build<Foo>()
.Without(foo => foo.Relation1)
.Without(foo => foo.Relation2)
.CreateMany();
Related
I am trying to mock a DbSet<> in Moq where I can add to the list of entities in the DbSet<>. In other words, a mutable DbSet<>.
I have some extension methods written for this, but have distilled the problem down into a single test.
I thought in Moq if you Setup the same call with the same parameters (filter), the Setup is replaced?
But, yet, this below unit test shows that it is added?
See 'below throws "Expected collection to contain 1 item(s), but found 2."'
[Fact]
public void Add2Test()
{
var contextMock = new Mock<IDbContext>();
List<MyEntity> data = new List<MyEntity>(){new MyEntity()};
var queryable = data.AsQueryable();
var mockDbSet = new Mock<DbSet<MyEntity>>();
mockDbSet.As<IQueryable<MyEntity>>().Setup(m => m.Provider).Returns(queryable.Provider);
mockDbSet.As<IQueryable<MyEntity>>().Setup(m => m.Expression).Returns(queryable.Expression);
mockDbSet.As<IQueryable<MyEntity>>().Setup(m => m.ElementType).Returns(queryable.ElementType);
mockDbSet.As<IQueryable<MyEntity>>().Setup(m => m.GetEnumerator()).Returns(queryable.GetEnumerator());
contextMock.Setups.Where(s => s.Expression.ReturnType == typeof(DbSet<MyEntity>)).Should().HaveCount(0);
contextMock.Setup(x => x.Set<MyEntity>()).Returns(mockDbSet.Object);
contextMock.Setups.Where(s => s.Expression.ReturnType == typeof(DbSet<MyEntity>)).Should().HaveCount(1);
// let's do it again
data = new List<MyEntity>() { new MyEntity() };
queryable = data.AsQueryable();
mockDbSet = new Mock<DbSet<MyEntity>>();
mockDbSet.As<IQueryable<MyEntity>>().Setup(m => m.Provider).Returns(queryable.Provider);
mockDbSet.As<IQueryable<MyEntity>>().Setup(m => m.Expression).Returns(queryable.Expression);
mockDbSet.As<IQueryable<MyEntity>>().Setup(m => m.ElementType).Returns(queryable.ElementType);
mockDbSet.As<IQueryable<MyEntity>>().Setup(m => m.GetEnumerator()).Returns(queryable.GetEnumerator());
contextMock.Setups.Where(s => s.Expression.ReturnType == typeof(DbSet<MyEntity>)).Should().HaveCount(1);
contextMock.Setup(x => x.Set<MyEntity>()).Returns(mockDbSet.Object);
// below throws "Expected collection to contain 1 item(s), but found 2."
contextMock.Setups.Where(s => s.Expression.ReturnType == typeof(DbSet<MyEntity>)).Should().HaveCount(1);
}
From my observations writing libraries such as EntityFrameworkCore.Testing, MemoryCache.Testing etc, Moq does not replace/override existing setups that are the same.
Though it's a Moq implementation detail, currently if you setup the same expression more than once the last setup added will be used.
void Main()
{
var mock = new Mock<IFoo>();
mock.Setup(x => x.Bar()).Returns("A");
mock.Setup(x => x.Bar()).Returns("B");
var mocked = mock.Object;
Console.WriteLine(mocked.Bar());
Console.WriteLine(mock.Setups.Select(x => x.ToString()));
}
public interface IFoo
{
public string Bar();
}
I'm trying to make a framework to abstract my Entity Layers, However for this to work I need automapper projects to work so I can Query my DTO's instead of Querying the Entities
[TestMethod]
public async Task Verify_Mapping_Projection_Behavior()
{
var projectionModifier = "Alabastar";
var services = this.GetRegisteredRestEzServiceCollection();
var serviceProvider = services.BuildServiceProvider();
var context = (AstootContext)serviceProvider.GetService<DbContext>();
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<User, UserDTO>().ForMember(x => x.FirstName,
o => o.MapFrom((entity, dto) => entity.FirstName + projectionModifier));
});
var mapper = config.CreateMapper();
// Hack: we'll verify exeuction happens in sql
// using the behavioral differene between in memory and sql (case insensitivity)
var sqlOnlyModifier = projectionModifier.ToUpper();
var userDTO = mapper.ProjectTo<UserDTO>(context.Users)
.Where(x => x.FirstName.Contains(sqlOnlyModifier))
.FirstOrDefault();
Assert.IsNotNull(userDTO);
}
My test failed, so I decided to materialize the projection directly. When I materialize I can see that my projectionModifier is not being added to the firstName property.
How can I get the project to map my modifier, so that I can use my DTO's as Sql Queryables?
The 3 parameter overload for MapFrom requires assignment. This can be resolved by using the 2 parameter overload.
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<User, UserDTO>()
.ForMember(dto => dto.FirstName,
opt => opt.MapFrom(entity => entity.FirstName + projectionModifier));
});
Trying to unit test the following MongoDb update function in C#.
var update = Builders<InvestorMongoDao>.Update
.Set(x => x.EmailAddress, command.EmailAddress);
await this.myDatabase.Users
.UpdateOneAsync(x => x.UserId == userId), update)
.ConfigureAwait(false);
I can easily check whether this function is called with a generic filter:
this.mockCollection
.Verify(x => x.UpdateOneAsync(It.IsAny<FilterDefinition<MyDao>>(),
It.IsAny<UpdateDefinition<MyDao>>(),
It.IsAny<UpdateOptions>(),
It.IsAny<CancellationToken>()));
However, I want to try and verify that it's being called with the expected parameter. I cannot seem to find a way to extract the parameter I want to check from FilterDefinition. I have tried this:
var foo = Builders<MyDao>.Filter.Eq("UserId", expectedUserId);
this.mockCollection
.Verify(x => x.UpdateOneAsync(It.Is<FilterDefinition<MyDao>>(a => a == foo),
It.IsAny<UpdateDefinition<MyDao>>(),
It.IsAny<UpdateOptions>(),
It.IsAny<CancellationToken>()));
But the test states the invocation is not performed. What am I doing wrong?
It appears you can approximate what's needed here by using Render.
var serializerRegistry = BsonSerializer.SerializerRegistry;
var documentSerializer = serializerRegistry.GetSerializer<MyDao>();
var expectedFilter = Builders<MyDao>.Filter.Eq("UserId", existingInvestor2.InvestorId);
this.mockCollection
.Verify(x => x.UpdateOneAsync(It.Is<FilterDefinition<MyDao>>(a => a.Render(documentSerializer, serializerRegistry) == expectedFilter.Render(documentSerializer, serializerRegistry)),
It.IsAny<UpdateDefinition<MyDao>>(),
It.IsAny<UpdateOptions>(),
It.IsAny<CancellationToken>()));
How can I write a unit test for this method:
public void ClassifyComments()
{
IEnumerable<Comment> hamComments = _commentRepository.FindBy(x => x.IsSpam == false);
IEnumerable<Comment> spamComments = _commentRepository.FindBy(x => x.IsSpam == true);
//....
}
The FindBy method takes an expression as a parameter:
public virtual IEnumerable<T> FindBy(Expression<Func<T, bool>> filter)
{
return dbSet.Where(filter).ToList();
}
This is my unit test so far:
IEnumerable<Comment> spamComments = Builder<Comment>.CreateListOfSize(10).All()
.With(x => x.Content = "spam spam spam")
.Build();
IEnumerable<Comment> hamComments = Builder<Comment>.CreateListOfSize(10).All()
.With(x => x.Content = "ham ham ham")
.Build();
var mockRepository = new Mock<IGenericRepository<Comment>>();
mockRepository
.Setup(x => x.FindBy(It.Is<Expression<Func<Comment, bool>>>(y => y.IsSpam == true)))
.Returns(spamComments);
mockRepository
.Setup(x => x.FindBy(It.Is<Expression<Func<Comment, bool>>>(y => y.IsSpam == true)))
.Returns(hamComments);
But I can't compile it, how can I change this test so that the mocks generate values for hamComments and spamComments.
Error 2 'System.Linq.Expressions.Expression>'
does not contain a definition for 'IsSpam' and no extension method
'IsSpam' accepting a first argument of type
'System.Linq.Expressions.Expression>'
could be found (are you missing a using directive or an assembly
reference?)
You're attempting to recreate the logic you want to test in your test and I think that is your mistake. Try this code:
IEnumerable<Comment> spamComments = Builder<Comment>.CreateListOfSize(10).All()
.With(x => x.Content = "spam spam spam")
.Build();
IEnumerable<Comment> hamComments = Builder<Comment>.CreateListOfSize(10).All()
.With(x => x.Content = "ham ham ham")
.Build();
// Bring both lists together as one (might be a better way to do this)
IEnumerable<Comment> allComments = spamComments.Union(hamComments);
var mockRepository = new Mock<IGenericRepository<Comment>>();
mockRepository
.Setup(x => x.FindBy(It.Is<Expression<Func<Comment, bool>>>())
.Returns(spamComments);
NOTE: I'm not a Moq expert, so that syntax above might not be 100% right
So the purpose of the code in your ClassifyComments method is to take a list of mixed Comment instances and split them up into their different classifications (spam and ham), so you just want your mockRepository to return a single list of comments.
Then it's up to the rest of your unit test to verify that your ClassifyComments did what it was supposed to do with the knowledge that it had 10 "spam" and 10 "ham" Comment instances.
So as an example, let's assume that your ClassifyComments looked like this:
public void ClassifyComments(out IEnumerable<Comment> spam, out IEnumerable<Comment> ham)
{
IEnumerable<Comment> hamComments = _commentRepository.FindBy(x => x.IsSpam == false);
IEnumerable<Comment> spamComments = _commentRepository.FindBy(x => x.IsSpam == true);
//....
// Set the out params
spam = spamComments;
ham = hamComments;
}
Your unit test would look like this:
public void TestClassifyComments() {
IEnumerable<Comment> spamComments = Builder<Comment>.CreateListOfSize(10).All()
.With(x => x.Content = "spam spam spam")
.Build();
IEnumerable<Comment> hamComments = Builder<Comment>.CreateListOfSize(10).All()
.With(x => x.Content = "ham ham ham")
.Build();
// Bring both lists together as one (might be a better way to do this)
IEnumerable<Comment> allComments = spamComments.Union(hamComments);
var mockRepository = new Mock<IGenericRepository<Comment>>();
mockRepository
.Setup(x => x.FindBy(It.Is<Expression<Func<Comment, bool>>>())
.Returns( (Expression<Func<Comment, bool>> predicate => spamComments.Where(predicate));
// Construct the class which has the ClassifyComments method
var sut = ...;
IEnumerable<Comment> ham;
IEnumerable<Comment> spam;
sut.ClassifyComments(out spam, out ham);
Assert.That(spam.Length, Is.EqualTo(10));
Assert.That(ham.Length, Is.EqualTo(10));
}
EDIT
Ok I did a little research on Moq and I think the above code is how you would do this with Moq.
I would like testing private method. When I setup FirstOrDefault method Moq thrown Exception. In my algorithm, I want check that, does my method properly create new objects.
See my code below.
//Arrange
var data = new List<TypeValue>();
var typeValueMockSet = new Mock<DbSet<TypeValue>>();
typeValueMockSet
.As<IList<TypeValue>>()
.Setup(m => m.GetEnumerator())
.Returns(data.GetEnumerator());
//throw the Error => Expression references a method that does not belong to the mocked object:
// m => m.FirstOrDefault<TypeValue>(It.IsAny<Expression`1>())
typeValueMockSet
.Setup(m => m.FirstOrDefault(It.IsAny<Expression<Func<TypeValue, bool>>>()))
.Returns(data.FirstOrDefault());
typeValueMockSet
.Setup(m => m.Add(It.IsAny<TypeValue>()))
.Returns((TypeValue vt) => vt)
.Callback((TypeValue vt) => data.Add(vt));
var mockContext = new Mock<EngineeringWorkEntities>();
mockContext.Setup(m => m.TypeValues).Returns(typeValueMockSet.Object);
int counter = 0;
mockContext
.Setup(m => m.SaveChanges())
.Returns(0)
.Callback(() => data
.ForEach(
(item) =>
{
item.Id = counter;
counter++;
}));
//Act
IMakro makroDateGenerate = new MakroDataGenerate(mockContext.Object);
var pObj = new PrivateObject(makroDateGenerate);
int r1 = (int)pObj.Invoke("GetTypeValueId", "0,2% k/k"); //2
You cannot mock FirstOrDefault because it is an extension method. It doesn't belongs to List<T> or anything else.
You cannot test private methods other than by using Reflection in the unit tests. This is very cumbersome. You should test the public interface anyway.
Either make the method public or internal. If you make it internal, you can allow the unit test project to see it by the use of the InternalsVisibleToAttribute.
[assembly:InternalsVisibleTo("MyUnitTestProject")]