I am using Elasticsearch .Net Client 6.x, and I have some code like:
if(this.elasticClient.IndexExists("indexName").Exists){
// do something
}
this.elasticClient.CreateIndex(
newIndex,
x => x.Settings(s => s.NumberOfShards(1)).Mappings(ms => ms.Map<T>(m => m.AutoMap())));
var searchResponse = client.Search<dynamic>(
s => s.AllTypes()
.Index(
new[] { "indexName1", "indexName"}).IgnoreUnavailable().Size(size).From(from).Query(
q => q.Bool(b => b.Must(m => m.SimpleQueryString(c => c.Query(query).Lenient().AnalyzeWildcard())))));
Now in my unit test, I'd like to test the exact descriptor passed to each method, how can I do this?
var existsResponse = new Mock<ExistsResponse>();
existsResponse.Setup(x => x.Exists).Returns(false); // Oops: can't do this since Exists is not virtual, abstract
this.elasticClient.Setup(x => x.IndexExists("indexName", null)).Returns(existsResponse.Object);
this.elasticClient.Verify(
x => x.CreateIndex("IndexName", It.Is<Func<CreateIndexDescriptor, ICreateIndexRequest>>(x => /*what goes here??*/)),
Times.Once);
this.elasticClient.Verify(
x => x.Search<dynamic>(It.Is<Func<SearchDescriptor<dynamic>>>(x => /*what goes here??*/)),
Times.Once);
Should I just simply wrap the elasticClient in a class and implement every method I used, and pass it as dependency injection?
Related
I need to send a lamda in function parameter
but when i do that i've error say
Expression of type 'System.Func2[KokazGoodsTransfer.Models.Receipt,System.Decimal]' cannot be used for parameter of type 'System.Linq.Expressions.Expression1[System.Func2[KokazGoodsTransfer.Models.Receipt,System.Decimal]]' of method 'System.Decimal Sum[Receipt](System.Linq.IQueryable1[KokazGoodsTransfer.Models.Receipt], System.Linq.Expressions.Expression1[System.Func2[KokazGoodsTransfer.Models.Receipt,System.Decimal]])' (Parameter 'arg1')'
example of code
var sum = await context.Receipts.GroupBy(c => c.ClientId).Select(c => new { c.Key, Sum = c.Sum(c=>c.Amount) }).ToListAsync();
it's work fine
but when i try this i see the error
Func<Receipt, Decimal> func = c => c.Amount;
var sum = await context.Receipts.GroupBy(c => c.ClientId).Select(c => new { c.Key, Sum = c.Sum(func) }).ToListAsync();
thank you
EF usually requires an expression tree to be able to translate the code into actual SQL query.
You can try something like this (though not tested, but in some cases such tricks worked as far as I remember):
Expression<Func<Receipt, Decimal>> func = c => c.Amount;
var sum = await context.Receipts
.GroupBy(c => c.ClientId)
.Select(c => new { c.Key, Sum = c.AsQueryable().Sum(func) })
.ToListAsync();
Otherwise you maybe will need either to build select statement expression manually (which is not that easy) or look into 3rd party library like LINQKit which allows to use Func's with some magic. Something along this lines:
Expression<Func<Receipt, Decimal>> func = c => c.Amount;
var sum = await context.Receipts
.AsExpandable() // or WithExpressionExpanding on the context DI set up
.GroupBy(c => c.ClientId)
.Select(c => new { c.Key, Sum = c.Sum(func.Compile()) })
.ToListAsync();
You have to use not Func but Expression<Func<Receipt, Decimal>>. But it also will be not translatable without third-party extensions. I would suggest to use LINQKit. It needs just configuring DbContextOptions:
builder
.UseSqlServer(connectionString) // or any other provider
.WithExpressionExpanding(); // enabling LINQKit extension
Then your query will work in the following way:
Expression<Func<Receipt, Decimal>> func = c => c.Amount;
var sum = await context.Receipts.GroupBy(c => c.ClientId)
.Select(c => new { c.Key, Sum = c.Sum(x => func.Invoke(x)) })
.ToListAsync();
I recently met with an automapper. I have a question, how i can map multiple objects from my repostiory in one DTO.
public QuestionProfile()
{
CreateMap<Question, GrammarQuestionDTO>()
.ForMember(g => g.Question, q => q.MapFrom(source => source.Text)).ReverseMap();
CreateMap<List<GrammarQuestionDTO>, TestDTO>()
.ForMember(t => t.GrammarQuestion, g => g.MapFrom(source => source)).ReverseMap();
CreateMap<Question, AuditionQuestionDTO>()
.ForMember(a => a.Question, q => q.MapFrom(source => source.Text))
.ForMember(a => a.Url, q => q.MapFrom(source => source.AudioFile.Url)).ReverseMap();
CreateMap<List<AuditionQuestionDTO>, TestDTO>()
.ForMember(t => t.AuditionQuestion, a => a.MapFrom(source => source)).ReverseMap();
}
how can I map all these 4 objects?
public async Task<TestDTO> GenerateTest(LevelType level)
{
var grammarQuestions = await _questionRepository.GetGrammarQuestionAsync(level);
var auditionQuestions = await _questionRepository.GetAuditionQuestionAsync(level);
var essayTopic = await _questionRepository.GetEssayTopicAsync(level);
var speakingTopic = await _questionRepository.GetSpeakingTopicAsync(level);
var test = _mapper.Map<TestDTO>(grammarQuestions);
test = _mapper.Map(test, auditionQuestions); //there will be a conversion error
return _mapper.Map<TestDTO>(grammarQuestions);
}
You need to map it without list, just map it one to one and AutoMapper will handle the collections:
CreateMap<AuditionQuestionDTO, TestDTO>()
.ForMember(t => t.AuditionQuestion,
a => a.MapFrom(source => source.<PropertyName>)).ReverseMap();
And then on the map you should:
test = _mapper.Map<List<AuditionQuestionDTO>>(test, auditionQuestions);
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 writing unit tests where the SUT (system under test) can undertake a wide variety of different configurations. Instead of adding a parameter for each combination, I decided to (or attempt) take an alternative, cleaner approach. For those that don't know, the Fixture object is from a library called AutoFixture, which handles seeding random test values.
Here is my failing test -
[Test]
public void Test()
{
var locate = Build(x => x.With(xx => xx.TicketNo, 123));
Assert.AreEqual(123, locate.TicketNo);
}
private Locate Build(Action<ICustomizationComposer<Locate>> customizationAction)
{
var fixture = new Fixture();
var customizationComposer = fixture.Build<Locate>();
customizationAction(customizationComposer);
var postProcessComposer = customizationComposer
.Without(x => x.Attachments)
.Without(x => x.Comments)
.Without(x => x.Reviews)
.Without(x => x.ScheduledCrew)
.Without(x => x.PendingDecision)
.Without(x => x.FinalDecision)
.Without(x => x.ConflictResolution);
return postProcessComposer.Create();
}
As you can, I'm attempting to use the Build method to create a Locate object with a set of ignore rules via the Without method calls. This is the baseline object I require for each test. Each test has the option to ignore additional fields or hard code field values via the With method call.
I would expect to pass because I set my Build lambda parameter to set the TicketNo property to 123. Instead, the test fails because AutoFixture seeds TicketNo with a random integer.
How can I achieve this?
Solution!
private Locate Build(Func<IPostprocessComposer<Locate>, IPostprocessComposer<Locate>> action)
{
var customizationComposer = _fixture.Build<Locate>();
var postProcessComposer = customizationComposer
.With(x => x.TicketNo, DateTime.Now.ToFileTime())
.With(x => x.On1CallNotified, false)
.Without(x => x.Attachments)
.Without(x => x.Comments)
.Without(x => x.Reviews)
.Without(x => x.ScheduledCrew)
.Without(x => x.PendingDecision)
.Without(x => x.FinalDecision)
.Without(x => x.ConflictResolution);
postProcessComposer = action(postProcessComposer);
return postProcessComposer.Create();
}
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")]