简体   繁体   中英

How can I setup the mockRepository return method to return an IEnumerable<T>?

I'm new to MOQ and I already done some coding before but this time I need to return 2 objects on a List of Tasks that I created. I tried using mockRepository.SetReturnsDefault() command but somehow it just don't work as the way I programmed to. I'm using this test that create two different Tasks and I just need to Update the first Tasks that I created (taskPrev).

I created a Handler to make the exceptions so that i can't create tasks that overlap others, and others business rules, and that Test i'm trying to Update a previous task and should return Sucess but when I run test it return all tasks that i added to the List tasks even when i'm using a function to filter those tasks.

The part that i'm using to filter is var tasks = await _repository.FindBy(x => x.Id.= command;Id); but it just return all the two tasks without filtering it.

I'd like to know if i'm using the moq on the wrong way or is other thing because i already search for many foruns and didn't find anything that could help me.

Here is the way i'm configuring moq to return the list:

//Criar 1ª Task
Task taskPrev = new Task(taskTypeId, projectId, costCenterId, Convert.ToDateTime(date), 
        startHour, startMinute, endHour, endMinute, workItem, timeSheetId, description);
taskPrev.Id = taskId;
//Criar 2ª Task
Task taskCurr = new Task(taskTypeId, projectId, costCenterId, Convert.ToDateTime(date), 
        endHour, startMinute, Convert.ToByte(endHour + 1), endMinute, workItem, timeSheetId, description);
taskCurr.Id = taskId + 1;

List<Task> tasks = new List<Task>();
tasks.Add(taskPrev);
tasks.Add(taskCurr);
// mockRepository.SetReturnsDefault(System.Threading.Tasks.Task.FromResult((IEnumerable<Task>)tasks));
mockRepository.Setup(x => x.FindBy(x => It.IsAny<IAsyncRepository<Task>>())).Returns(System.Threading.Tasks.Task.FromResult((IEnumerable<Task>)tasks.Where(x => x.Id == taskCurr.Id)));

Using mockRepository.SetReturnsDefault() return both tasks and dont filter; Using mockRepository.SetReturnsDefault() and mockRepository.Setup() makes the same as using only SetReturnsDefault(); And using only mockRepository.Setup() return empty.

The Test code that i'm using:

[Theory]
[InlineData(1,1,1,"2020-03-25",9,0,10,0,"",1,"valor",1,5)]
[InlineData(2,2,2,"2020-03-28",11,0,12,0,"Valor",2,"valor",3,6)]
[InlineData(3,4,5,"2020-03-04",13,0,14,0,"",6,"valor",7,7)]
//Deve permitir editar uma task criada anteriormente a nova task
//EX: 1ª task finaliza as 10:00 e a nova inicia as 10:00, deve permitir uma alteração da 1ª task
public async void Update_PreviousTask_Return_Success_When_CurrentTask_HasStartHour_Equals_PreviousTask_EndHour(
    int taskTypeId, int projectId, int costCenterId, string date, byte startHour, byte startMinute,
    byte endHour, byte endMinute, string workItem, int timeSheetId, string description, int employeeId, int taskId)
    {
        //São necessários apenas para criação do handler
        var mockRepository = new  Mock<IAsyncRepository<Task>>();
        var mockRepositoryTimeSheet = new  Mock<IAsyncRepository<TimeSheet>>();
        var mockRepositoryProject = new  Mock<IAsyncRepository<Project>>();            

        //Cria handler
        TaskHandler handler = new TaskHandler(mockRepository.Object, 
        mockRepositoryTimeSheet.Object, mockRepositoryProject.Object);

        //Cria Project
        Project project = new Project("nameProject", 1, true, 1);
        project.Id = projectId;

        // List<Project> projects =new List<Project>();
        // projects.Add(project);
        mockRepositoryProject.SetReturnsDefault(System.Threading.Tasks.Task.FromResult(project));   

        //Cria timeSheet 
        TimeSheet timeSheet = new TimeSheet(1, Convert.ToDateTime(date).AddDays(-30), Convert.ToDateTime(date).AddDays(30), employeeId);
        timeSheet.Id = timeSheetId;

        List<TimeSheet> timeSheets = new List<TimeSheet>();
        timeSheets.Add(timeSheet);
        mockRepositoryTimeSheet.SetReturnsDefault(System.Threading.Tasks.Task.FromResult((IEnumerable<TimeSheet>)timeSheets));

        //Criar 1ª Task
        Task taskPrev = new Task(taskTypeId, projectId, costCenterId, Convert.ToDateTime(date), 
                startHour, startMinute, endHour, endMinute, workItem, timeSheetId, description);
        taskPrev.Id = taskId;
        //Criar 2ª Task
        Task taskCurr = new Task(taskTypeId, projectId, costCenterId, Convert.ToDateTime(date), 
                endHour, startMinute, Convert.ToByte(endHour + 1), endMinute, workItem, timeSheetId, description);
        taskCurr.Id = taskId + 1;

        List<Task> tasks = new List<Task>();
        tasks.Add(taskPrev);
        tasks.Add(taskCurr);
        // mockRepository.SetReturnsDefault(System.Threading.Tasks.Task.FromResult((IEnumerable<Task>)tasks));
        mockRepository.Setup(x => x.FindBy(x => It.IsAny<IAsyncRepository<Task>>())).Returns(System.Threading.Tasks.Task.FromResult((IEnumerable<Task>)tasks.Where(x => x.Id == taskCurr.Id)));

        //Command para criar a task
        UpdateTaskCommand command = new UpdateTaskCommand(taskTypeId, projectId, costCenterId, Convert.ToDateTime(date),
        startHour, startMinute, endHour, endMinute, workItem, "descrição Teste", taskId, employeeId);

        //Act
        var retorno = (CommandResult)await handler.Handle(command);

        //Assert
        Assert.True(retorno.Sucess);
        }

And the Handler part that is not working as it should be:

var tasks = await _repository.FindBy(x => x.Id != command.Id);
var retorno = tasks.FirstOrDefault(x => (x.TimeSheetId == command.TimeSheetId && x.Date.Date == command.Date.Date)
                                         &&
                                         (
                                             (
                                                 (new TimeSpan(x.StartHour, x.StartMinute, 0) <= new TimeSpan(command.StartHour, command.StartMinute, 0))
                                              && (new TimeSpan(x.EndHour, x.EndMinute, 0) > new TimeSpan(command.StartHour, command.StartMinute, 0))
                                              )
                                              ||
                                              (
                                                 (new TimeSpan(x.EndHour, x.EndMinute, 0) >= new TimeSpan(command.EndHour, command.EndMinute, 0))
                                              && (new TimeSpan(x.StartHour, x.StartMinute, 0) < new TimeSpan(command.EndHour, command.EndMinute, 0))
                                              )
                                              ||
                                              (
                                                 (new TimeSpan(x.StartHour, x.StartMinute, 0) >= new TimeSpan(command.StartHour, command.StartMinute, 0))
                                              && (new TimeSpan(x.EndHour, x.EndMinute, 0) <= new TimeSpan(command.EndHour, command.EndMinute, 0))
                                              )

                                         ));

if (retorno != null)
    throw new BusinessException("Não é permitido criar novos registros que se sobreponham a outros existentes", 
                                nameof(command.StartHour) + ", " + nameof(command.StartMinute) + ", " +
                                nameof(command.EndHour) + ", " + nameof(command.EndMinute), ErrorsEnum.ResourceInvalidField);

I think you have some confusion in how you're defining the expected parameter in your Setup method.

To illustrate the issue, let's look at a setup that doesn't involve lambdas:

var myMock = new Mock<IMyThing>();
myMock.Setup(m => m.GetById(7)).Returns(new Thing());

This is a setup for a call to GetById where the parameter is exactly 7. If the code you are testing calls GetById(7), it will get a Thing object. If the calling code passes anything other than 7, then the setup will not be matched, and the return will be null.

You can make your setup more flexible by using It.IsAny():

var myMock = new Mock<IMyThing>();
myMock.Setup(m => m.GetById(It.IsAny<int>())).Returns(new Thing());

Now it doesn't matter what integer your calling code passes to GetById() - the setup will always be matched, and you'll always get a non-null Thing.

With that understanding in place, let's look at your setup:

mockRepository.Setup(x => x.FindBy(x => It.IsAny<IAsyncRepository<Task>>())).Returns(//stuff);

The FindBy method takes a predicate of type Func<Task,bool> , and here you have provided a specific predicate: x => It.IsAny<IAsyncRepository<Task>>() . Because you provided a specific parameter value, then the calling code must either exactly match that specific parameter, or the setup won't be matched. The predicate your calling code is passing to FindBy does not match because (x => x.Id.= command.Id) != (x => It.IsAny<IAsyncRepository<Task>>()) , and since the setup is not matched, you return null (or if SetReturnsDefault has been called, it will return whatever the default return is).

If you want your setup to match any lambda your calling code might send in, it should look like this:

mockRepository.Setup(x => x.FindBy(It.IsAny<Func<Task,bool>>())).Returns(//stuff);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM