How to fill a Mock<DbSet> in Nunit with Moq? - testing

I am trying to fill a mock dbset with a testentity but I only get exception after exception. I am very new to Nunit testing and haven't really got the hang of it. I am trying to test a simple delete method in my repository, here is the code for the method:
public async Task DeleteQuestion(Question questionToRemove)
{
if (questionToRemove is not null)
{
var questionsAnswers = await _context.Answers.Where(a => a.Question == questionToRemove).ToListAsync();
foreach (Answer a in questionsAnswers)
{
_context.Answers.Remove(a);
await _context.SaveChangesAsync();
}
_context.Questions.Remove(questionToRemove);
await _context.SaveChangesAsync();
var questions = await _context.Questions.Where(q => q.Quiz == questionToRemove.Quiz).ToListAsync();
int order = 1;
foreach (Question question in questions)
{
question.QuestionOrderId = order;
await _context.SaveChangesAsync();
order++;
}
}
}
And here is the test that I have written:
public async Task DeleteQuestionFunction()
{
//Arrange
Question testQuestion = new Question { QuestionId = 1, QuestionText = "Test" };
Answer testAnswer = new Answer { Question = testQuestion, AnswerId = 1, AnswerText = "TestAnswer" };
_appDBContextMock.SetupAdd(x => x.Questions.Add(testQuestion));
_appDBContextMock.SetupAdd(x => x.Answers.Add(testAnswer));
//Act
var questionListcomponent = new QuestionListComponent();
questionListcomponent.DeleteQuestion(testQuestion);
var testresult = await _questionRepositoryMock.Object.GetQuestionById(testQuestion.QuestionId);
//Assert
Assert.That(testresult, Is.Null);
}
When I only used the Setup method I got this exception:
System.NotSupportedException : Unsupported expression: x =>
x.Questions Non-overridable members (here: AppDbContext.get_Questions)
may not be used in setup / verification expressions.
and right now with the SetupAdd function I get this exception:
System.ArgumentException : Can not instantiate proxy of class:
TietoQuiz.Models.DbContexts.AppDbContext. Could not find a
parameterless constructor. (Parameter 'constructorArguments')
I think my problem is that I don't know how to set up a mock dbset properly. I tried to Google, but I found so many different ways and so many comments saying "that is not recommended/ the wrong way"! It is very confusing for a newbie, so I hope someone here can help!

If you want to write a test by using a context, you must create your own context and verify the data after running it. You cannot use mocks with non overridable methods.
You must use a temporary file to create this context not to change your production database.

Related

Since 'func' is an async method that returns 'Task',a return keyword must not be followed by an object expression. Did you intend to return 'Task<T>'?

Hello My Program got this error and i dont know why?
Since 'InsertToHomeSecondPagesTableJob.Execute(IJobExecutionContext)' is an async method that returns 'Task', a return keyword must not be followed by an object expression. Did you intend to return 'Task'?
this is my code
public async Task Execute(IJobExecutionContext context)
{
var PagesScoreNewsHomePageTable = new PagesScoreNewsHomePageTable()
{
PagesID = 1,
UserID = 22,
Author = "jack"
};
_db.AddAsync(PagesScoreNewsHomePageTable);
_db.SaveChangesAsync();
return Task.CompletedTask;
}
how can i solve this error?
The simple and recommended way to solve this problem is using await keywords.
The async and await keywords in C# are the heart of async programming.
By using those two keywords, you can use resources in .NET Framework,
.NET Core, or the Windows Runtime to create an asynchronous method
almost as easily as you create a synchronous method.
You just need to change your code like:
public async Task Execute(IJobExecutionContext context)
{
var PagesScoreNewsHomePageTable = new PagesScoreNewsHomePageTable()
{
PagesID = 1,
UserID = 22,
Author = "jack"
};
await _db.AddAsync(PagesScoreNewsHomePageTable);
await _db.SaveChangesAsync();
}
More details about async you can refer to this Docs.

Custom Result in Net 6 Minimal API

In ASP.NET Core 5 I had a custom Action Result as follows:
public class ErrorResult : ActionResult {
private readonly IList<Error> _errors;
public ErrorResult(IList<Error> errors) {
_errors = errors;
}
public override async Task ExecuteResultAsync(ActionContext context) {
// Code that creates Response
await result.ExecuteResultAsync(context);
}
}
Then on a Controller action I would have:
return new ErrorResult(errors);
How to do something similar in NET 6 Minimal APIs?
I have been looking at it and I think I should implement IResult.
But I am not sure if that is the solution or how to do it.
I have recently been playing around with minimal APIs and and working on global exception handling. Here is what I have come up with so far.
Create a class implementation of IResult
Create a constructor which will take an argument of the details you want going into your IResult response. APIErrorDetails is a custom implementation of mine similar to what you'd see in ProblemDetails in MVC. Method implementation is open to whatever your requirements are.
public class ExceptionAllResult : IResult
{
private readonly ApiErrorDetails _details;
public ExceptionAllResult(ApiErrorDetails details)
{
_details = details;
}
public async Task ExecuteAsync(HttpContext httpContext)
{
var jsonDetails = JsonSerializer.Serialize(_details);
httpContext.Response.ContentType = MediaTypeNames.Application.Json;
httpContext.Response.ContentLength = Encoding.UTF8.GetByteCount(jsonDetails);
httpContext.Response.StatusCode = _details.StatusCode;
await httpContext.Response.WriteAsync(jsonDetails);
}
}
Return result in your exception handling middleware in your Program.cs file.
app.UseExceptionHandler(
x =>
{
x.Run(
async context =>
{
// https://learn.microsoft.com/en-us/aspnet/core/fundamentals/error-handling?view=aspnetcore-6.0
var exceptionFeature = context.Features.Get<IExceptionHandlerPathFeature>();
// Whatever you want for null handling
if (exceptionFeature is null) throw new Exception();
// My result service for creating my API details from the HTTP context and exception. This returns the Result class seen in the code snippet above
var result = resultService.GetErrorResponse(exceptionFeature.Error, context);
await result.ExecuteAsync(context); // returns the custom result
});
}
);
If you still want to use MVC (Model-View-Controller), you still can use Custom ActionResult.
If you just want to use Minimal APIs to do the response, then you have to implement IResult, Task<IResult> or ValueTask<IResult>.
app.MapGet("/hello", () => Results.Ok(new { Message = "Hello World" }));
The following example uses the built-in result types to customize the response:
app.MapGet("/api/todoitems/{id}", async (int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? Results.Ok(todo)
: Results.NotFound())
.Produces<Todo>(StatusCodes.Status200OK)
.Produces(StatusCodes.Status404NotFound);
You can find more IResult implementation samples here: https://github.com/dotnet/aspnetcore/tree/main/src/Http/Http.Results/src
Link: Minimal APIs overview | Microsoft Docs

Entity Framework Core: New transaction is not allowed because there are other threads running in the session

I have a database with a hierarchy of categories. Each category has a parentcategoryid. I call the following function to load the top level categories and then it recursively calls itself to load all the children.
However, I get the following error:
SqlException: New transaction is not allowed because there are other
threads running in the session.
public async Task LoadCategoriesAsync()
{
await LoadCategoriesByParentId(null);
}
private async Task LoadCategoriesByParentId(int? sourceParentId, int? parentId)
{
var sourceCategories = _dbContext.SourceCategory.Where(c => c.ParentCategoryId == sourceParentId);
foreach (var sourceCategory in sourceCategories)
{
var newCategory = new Category()
{
Name = sourceCategory.Name,
Description = sourceCategory.Description,
ParentCategoryId = parentId
};
_dbContext.Category.Add(newCategory);
await _dbContext.SaveChangesAsync();
//category.EntityId = newCategory.Id;
//_dbContext.SourceCategory.Update(category);
//await _dbContext.SaveChangesAsync();
await LoadCategoriesByParentId(sourceCategory.CategoryId, newCategory.Id);
}
}
Your Where() statement doesn't retrieve the data; just "opens the cursor" (in old-speak). So, you can't do SaveChange(). The simplest solution is to convert IEnumerable to List or Array:
var rootCategories = _dbContext.SourceCategory.Where(c => c.ParentCategoryId == parentId).ToList();
But I would strongly recommend you google the error and understand why it is happening. To do this recursively is begging for trouble

flutter serialize son to list objects throws exception

I have a .net server web api call that I am trying to port the client part to Flutter from Xamarin. mostly impressed with flutter/Dart except the json serialization/deserialization is a pain! my api returns a list of exercise routines that have embedded list of machines. this is pretty simp and normal stuff. my generated JSON looks like :
[
{"id":1,"
Name":"back",
"userid":1,
"cloned":0,
"Machines":
[
{"machineid":2,
"Name":"Leg Extension","PictureUrl":"https://l},
{"machineid":3,"Name":"yoga ball","PictureUrl":"https://
}
I originally tried the manual approach with dart.convert and things worked for my serializing a list of routines. however then I decided to use the code generation as described here my code thru following exception when I called jsonDecode:
type 'List' is not a subtype of type 'Map'
my flutter UI code looks like:
_fetchData() async {
setState(() {
isLoading = true;
});
final response =
await http.get("http://fitnesspal.azurewebsites.net/api/routines");
if (response.statusCode == 200) {
// list = (json.decode(response.body) as List)
// .map((data) => new Routine.fromJson(data))
// .toList();
// final jsonResponse = json.decode(response.body);
try {
String json1 = response.body;
Map map1 = jsonDecode(json1);
var test = Routine.fromJson(map1);
}
catch (e) {
print(e.toString());
}
setState(() {
isLoading = false;
});
} else {
throw Exception('Failed to load photos');
}
}
import 'package:json_annotation/json_annotation.dart';
import 'package:fitnesspal/Models/Machine.dart';
part 'Routine.g.dart';
#JsonSerializable(nullable: false)
class Routine{
final int id;
final String name;
#JsonKey(name: 'Machines')
List<Machine> Machines;
Routine({this.id,this.name,this.Machines});
factory Routine.fromJson(Map<String, dynamic> json) =>
_$RoutineFromJson(json);
Map<String, dynamic> toJson() => _$RoutineToJson(this);
}
I followed the described code generation steps
This doesn't work because json1 is a List of objects, not a Map.
Map map1 = jsonDecode(json1);
Try using this :
List list = jsonDecode(json1);
And get the first element just for testing (in a real scenario you will have to loop the list)
var test = Routine.fromJson(list[0]);
sorry the above was DFU error with stackoverflow. your idea worked but to get the list of routines that I wanted I ended up with:
list = (jsonDecode(response.body) as List)
.map((data) => new Routine.fromJson(data))
.toList();
I then use the routine name in my listBuilder and looks good so feeling pretty good but then I need to pass the embedded machine list to my list of machines widget. so I add a stateful widget called MachineList as follows: notice I setup my constructor to accept the List
class MachineList extends StatefulWidget {
final List<Machine> machines;
MachineList({Key key, this.machines}) : super(key: key);
#override
_MachineListState createState() => _MachineListState(machines);
}
then back in main.dart I want to navigate in the list item ontap :
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MachineList(
machines: list[index].machines)
)
);
lib/main.dart:122:82: Error: The argument type 'dart.core::List<#lib1::Machine>' can't be assigned to the parameter type 'dart.core::List<#lib2::Machine>
OMG where is it getting lib2 from
**** found my issue a case mismatch on the import In Dart, two libraries are the same if, and only if, they are imported using the same URI. If two different URIs are used, I had .../Models/. and ../models
painful learning experience as did not realize Dart was so sensitive as to used to c#

Structuring tests (or property) for this reactive ui scenario

I'm not sure the correct way to structure this test. I've got a view model here:
public class ViewModel
{
public ReactiveCommand PerformSearchCommand { get; private set; }
private readonly ObservableAsPropertyHelper<bool> _IsBusy;
public bool IsBusy
{
get { return _IsBusy.Value; }
}
public ViewModel(IAdventureWorksRepository _awRepository)
{
PerformSearchCommand = new ReactiveCommand();
PerformSearchCommand.RegisterAsyncFunction((x) =>
{
return _awRepository.vIndividualCustomers.Take(1000).ToList();
}).Subscribe(rval =>
{
CustomerList = rval;
SelectedCustomer = CustomerList.FirstOrDefault();
});
PerformSearchCommand.IsExecuting.ToProperty(this, x => x.IsBusy, out _IsBusy);
PerformSearchCommand.Execute(null); // begin executing immediately
}
}
The dependency is a data access object to AdventureWorks
public interface IAdventureWorksRepository
{
IQueryable<vIndividualCustomer> vIndividualCustomers { get; }
}
Finally, my test looks something like this:
[TestMethod]
public void TestTiming()
{
new TestScheduler().With(sched =>
{
var repoMock = new Mock<IAdventureWorksRepository>();
repoMock.Setup(x => x.vIndividualCustomers).Returns(() =>
{
return new vIndividualCustomer[] {
new vIndividualCustomer { FirstName = "John", LastName = "Doe" }
};
});
var vm = new ViewModel(repoMock.Object);
Assert.AreEqual(true, vm.IsBusy); //fails?
Assert.AreEqual(1, vm.CustomerList.Count); //also fails, so it's not like the whole thing ran already
sched.AdvanceTo(2);
Assert.AreEqual(1, vm.CustomerList.Count); // success
// now the customer list is set at tick 2 (not at 1?)
// IsBusy was NEVER true.
});
}
So the viewmodel should immediately begin searching upon load
My immediate problem is that the IsBusy property doesn't seem to get set in the testing scheduler, even though it seems to work fine when I run the code normally. Am I using the ToProperty method correctly in the view model?
More generally, what is the proper way to do the full 'time travel' testing when my object under test has a dependency like this? The issue is that unlike most testing examples I'm seeing, the called interface is not an IObservable. It's just a synchronous query, used asynchronously in my view model. Of course in the view model test, I can mock the query to do whatever rx things I want. How would I set this up if I wanted the query to last 200 ticks, for example?
So, you've got a few things in your code that is stopping you from getting things to work correctly:
Don't invoke commands in ViewModel Constructors
First, calling Execute in the constructor means you'll never see the state change. The best pattern is to write that command but not execute it in the VM immediately, then in the View:
this.WhenAnyValue(x => x.ViewModel)
.InvokeCommand(this, x => x.ViewModel.PerformSearchCommand);
Move the clock after async actions
Ok, now that we can properly test the before and after state, we have to realize that after every time we do something that normally would be async, we have to advance the scheduler if we use TestScheduler. This means, that when we invoke the command, we should immediately advance the clock:
Assert.IsTrue(vm.PerformSearchCommand.CanExecute(null));
vm.PerformSearchCommand.Execute(null);
sched.AdvanceByMs(10);
Can't test Time Travel without IObservable
However, the trick is, your mock executes code immediately, there's no delay, so you'll never see it be busy. It just returns a canned value. Unfortunately, injecting the Repository makes this difficult to test if you want to see IsBusy toggle.
So, let's rig the constructor a little bit:
public ViewModel(IAdventureWorksRepository _awRepository, Func<IObservable<List<Customer>>> searchCommand = null)
{
PerformSearchCommand = new ReactiveCommand();
searchCommand = searchCommand ?? () => Observable.Start(() => {
return _awRepository.vIndividualCustomers.Take(1000).ToList();
}, RxApp.TaskPoolScheduler);
PerformSearchCommand.RegisterAsync(searchCommand)
.Subscribe(rval => {
CustomerList = rval;
SelectedCustomer = CustomerList.FirstOrDefault();
});
PerformSearchCommand.IsExecuting
.ToProperty(this, x => x.IsBusy, out _IsBusy);
}
Set up the test now
Now, we can set up the test, to replace PerformSearchCommand's action with something that has a delay on it:
new TestScheduler().With(sched =>
{
var repoMock = new Mock<IAdventureWorksRepository>();
var vm = new ViewModel(repoMock.Object, () =>
Observable.Return(new[] { new vIndividualCustomer(), })
.Delay(TimeSpan.FromSeconds(1.0), sched));
Assert.AreEqual(false, vm.IsBusy);
Assert.AreEqual(0, vm.CustomerList.Count);
vm.PerformSearchCommand.Execute(null);
sched.AdvanceByMs(10);
// We should be busy, we haven't finished yet - no customers
Assert.AreEqual(true, vm.IsBusy);
Assert.AreEqual(0, vm.CustomerList.Count);
// Skip ahead to after we've returned the customer
sched.AdvanceByMs(1000);
Assert.AreEqual(false, vm.IsBusy);
Assert.AreEqual(1, vm.CustomerList.Count);
});