Xunit.net: Validating model returned by an async ASP.NET method - asp.net-web-api

I have been writing unit testing for the API. I need to check whether values inside the model returned by the action method are expected or not.
[Fact]
public async Task MerchantController_GetMGetProductByMerchantId_Merchant()
{
//Arrange
var merchantId = 1000;
var merchant = new Merchant
{
MerchantId = merchantId,
MerchantEmail = "akhil#gmail.com",
MerchantName="akhil",
MerchantPassword="12345",
ConfirmPassword="12345",
};
A.CallTo(() => _merchantRepository.GetMerchantByID(1000)).Returns(merchant);
var MerchantController = new MerchantController(_merchantRepository);
//Act
var result = MerchantController.GetMerchant(merchantId);
//Assert
result.Should()
.BeOfType<Task<ActionResult<Merchant>>>();
Assert.True(merchant.Equals(result));
}
How can I check result.MerchantEmail and akhil#gmail.com are equal in the assert.
controller with the action method GetMerchant
[HttpGet("{id}")]
public async Task<ActionResult<Merchant>> GetMerchant(int id)
{
try
{
return await _repository.GetMerchantByID(id);
}
catch
{
return NotFound();
}
}
Repository for the 'GetMerchantByID'
public async Task<Merchant> GetMerchantByID(int MerchantId)
{
return await _context.Merchants.FindAsync(MerchantId);
}
I need to check the value contained in the merchant model and how I can do it.
Merchant model
public class Merchant
{
[Key]
public int MerchantId { get; set; }
[Required(ErrorMessage = "Field can't be empty")]
[DataType(DataType.EmailAddress, ErrorMessage = "E-mail is not valid")]
public string? MerchantEmail { get; set; }
public string? MerchantName { get; set; }
[DataType(DataType.PhoneNumber)]
[Display(Name = "Phone Number")]
public string? MerchantPhoneNumber { get; set; }
[Display(Name = "Please enter password"), MaxLength(20)]
public string? MerchantPassword { get; set; }
[NotMapped]
[Display(Name = "ConfirmPassword")]
[Compare("MerchantPassword", ErrorMessage = "Passwords don not match")]
public string? ConfirmPassword { get; set; }
}
can someone help me to find a way if it is possible or suggest some resources

Some notes:
GetMerchant returns a Task<T>, so you need to await this call.
ActionResult<T> supports an implicit cast to T
Since Merchant is a class, using Equals will use reference equality. In your particular case, you're assuming that the same instance of Merchant that was passed into the controller is returned. Then you also don't need to use BeOfType.
You're mixing FluentAssertions and xUnit assertions.
So, you can rewrite the last part as:
// Act
Merchant result = await MerchantController.GetMerchant(merchantId);
// Assert
result.Should().BeSameAs(merchant);
One final design-related comment. A controller is an implementation detail of an HTTP API. So you really should be testing the HTTP by either using OWIN (in .NET 4.x) or the HostBuilder in .NET Core and later such as is done here.

The changes I made are given, to get the value from the return type from the instance of the ActionResult use (ActionResultinstance).Value it will separate the value from return type.
[Fact]
public async Task MerchantController_GetMGetProductByMerchantId_Merchant()
{
//Arrange
var merchantId = 1000;
Merchant merchant = new Merchant
{
MerchantId = merchantId,
MerchantEmail = "akhil#gmail.com",
MerchantName = "akhil",
MerchantPassword = "12345",
ConfirmPassword = "12345",
};
A.CallTo(() => _merchantRepository.GetMerchantByID(1000)).Returns(merchant);
var MerchantController = new MerchantController(_merchantRepository);
//Act
ActionResult<Merchant> TempResult =await MerchantController.GetMerchant(merchantId);
var result = TempResult.Value;
//Assert
result.Should().BeOfType<Merchant>();
}

Related

LUIS ActionBinding Param Library doesnt display if enum

If I specify as enum then it doesn't get displayed in the dialog. Can anyone help to point out if am missing some thing?
[LuisActionBinding("CollPay", FriendlyName = "Reminder")]
public class CollPayAction : BaseLuisAction
{
public enum PaymentAmtOptions
{
[Terms(new string[] { "Full Payment", "Entire Amount", "Full Due Amount" })]
FullPayment = 1,
[Terms(new string[] { "Clubbed Payment", "Combined Payment" })]
CombinedPayment
};
[Required(ErrorMessage = "Are you planning to make a separate payment or combined one?")]
[LuisActionBindingParam(CustomType = "BOPYMTOPTION", Order = 2)]
[Template(TemplateUsage.EnumSelectOne, "Are you planning to make a separate payment or combined one? {||}",
"How would you like to make the payment - separate for each Invoice(or) clubbed with other pending dues? {||}")]
public PaymentAmtOptions PaymentAmount { get; set; }
public override Task<object> FulfillAsync()
{
var result = string.Format("Hello! You have reached the CollPay intent");
return Task.FromResult((object)result);
}
}
Thanks for reporting this, it was certainly an issue. The good news is that a PR with a patch was already created.
Once the PR is approved, you will have to update your code:
-To use the updated library
-To validate the enum value. Below you will find how the code could look like:
[LuisActionBinding("CollPay", FriendlyName = "Reminder")]
public class CollPayAction : BaseLuisAction
{
public enum PaymentAmtOptions
{
None = 0, // default - no option selected
FullPayment = 1,
CombinedPayment = 2
};
// custom validator for my enum value
public class ValidPaymentAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
return value is PaymentAmtOptions && ((PaymentAmtOptions)value) != PaymentAmtOptions.None;
}
}
[ValidPayment(ErrorMessage = "Are you planning to make a separate payment [FullPayment] or combined one [CombinedPayment]?")]
[LuisActionBindingParam(CustomType = "BOPYMTOPTION", Order = 2)]
public PaymentAmtOptions PaymentAmount { get; set; }
public override Task<object> FulfillAsync()
{
var result = string.Format("Hello! You have reached the CollPay intent");
return Task.FromResult((object)result);
}
}

RavenDB, Linq: Build an expression from a Property inside a nested hierarchy

I stored the objects of the following classes in a ravendb database:
public class Continent
{
public string Id { get; set; }
public string Name { get; set; }
public List<Country> Countries { get; set; }
}
public class Country
{
public string Name { get; set; }
public List<Province> Provinces { get; set; }
}
public class Province
{
public string Name { get; set; }
public List<City> Cities { get; set; }
}
public class City
{
public string Name { get; set; }
public string Address { get; set; }
}
I want to write a method that searches Continents having a specific city. The latter is a parameter of my method. In this method, I want to execute a dynamic query like the following: query= session.Query().Where(ConditionOnTheSearchedCity). But I can not formulate the Expression "ConditionOnTheSearchedCity" because I can not iterate till the Name of each City. In fact, to create an expression based on the Name of the City, I've tried the following which is not working:
ParameterExpression parameterExpression = Expression.Parameter(typeof(Continent), "p");
Expression NameExpression = Expression.PropertyOrField(
Expression.PropertyOrField(
Expression.PropertyOrField(
Expression.PropertyOrField(parameterExpression, "Countries"), "Provinces"),
"Cities"),
"Name");
Can you please help me? Thanks in advance
Why are you going to all the trouble of dynamically building Linq?
Why not just use the RavenDB's DocumentQuery API which allows you to easily build queries dynamically?
As I mentioned in the comments, the question is too broad, so I'll give you just a starting point by providing an example. For more information, take a look at How to: Use Expression Trees to Build Dynamic Queries.
Let have a parameter string cityName and want a filter like this
Expression<Func<Continent, bool>> filter = continent =>
continent.Countries.Any(country =>
country.Provinces.Any(province =>
province.Cities.Any(city => city.Name == cityName)));
It can be build dynamically like this
var city = Expression.Parameter(typeof(City), "city");
var cityCondition = Expression.Equal(Expression.PropertyOrField(city, "Name"), Expression.Constant(cityName));
var province = Expression.Parameter(typeof(Province), "province");
var provinceCondition = Expression.Call(
typeof(Enumerable), "Any", new[] { city.Type },
Expression.PropertyOrField(province, "Cities"),
Expression.Lambda(cityCondition, city));
var country = Expression.Parameter(typeof(Country), "country");
var countryCondition = Expression.Call(
typeof(Enumerable), "Any", new[] { province.Type },
Expression.PropertyOrField(country, "Provinces"),
Expression.Lambda(provinceCondition, province));
var continent = Expression.Parameter(typeof(Continent), "continent");
var continentCondition = Expression.Call(
typeof(Enumerable), "Any", new[] { country.Type },
Expression.PropertyOrField(continent, "Countries"),
Expression.Lambda(countryCondition, country));
var filter = Expression.Lambda<Func<Continent, bool>>(continentCondition, continent);

Dynamic LINQ: Comparing Nested Data With Parent Property

I've a class with following structure:
public class BestWayContext
{
public Preference Preference { get; set; }
public DateTime DueDate { get; set; }
public List<ServiceRate> ServiceRate { get; set; }
}
public class ServiceRate
{
public int Id { get; set; }
public string Carrier { get; set; }
public string Service { get; set; }
public decimal Rate { get; set; }
public DateTime DeliveryDate { get; set; }
}
and I've dynamic linq expression string
"Preference != null && ServiceRate.Any(Carrier == Preference.Carrier)"
and I want to convert above string in Dynamic LINQ as follows:
var expression = System.Linq.Dynamic.DynamicExpression.ParseLambda<BestWayContext, bool>(condition, null).Compile();
But it showing following error:
Please correct me what am I doing wrong?
It looks like you wanted to do something like this:
var bwc = new BestWayContext
{
Preference = new Preference { Carrier = "test" },
DueDate = DateTime.Now,
ServiceRate = new List<ServiceRate>
{
new ServiceRate
{
Carrier = "test",
DeliveryDate = DateTime.Now,
Id = 2,
Rate = 100,
Service = "testService"
}
}
};
string condition = "Preference != null && ServiceRate.Any(Carrier == #0)";
var expression = System.Linq.Dynamic.DynamicExpression.ParseLambda<BestWayContext, bool>(condition, bwc.Preference.Carrier).Compile();
bool res = expression(bwc); // true
bwc.ServiceRate.First().Carrier = "test1"; // just for testing this -> there is only one so I've used first
res = expression(bwc); // false
You want to use Preference which belong to BestWayContext but you didn't tell the compiler about that. If i write your expression on Linq i will do as follows:
[List of BestWayContext].Where(f => f.Preference != null && f.ServiceRate.Where(g => g.Carrier == f.Preference.Carrier)
);
As you see i specified to use Preference of BestWayContext.

Getting an Enum to display on client side

I'm having hard time understanding how to convert an Enum value to it's corresponding name. My model is as follows:
public class CatalogRule
{
public int ID { get; set; }
[Display(Name = "Catalog"), Required]
public int CatalogID { get; set; }
[Display(Name = "Item Rule"), Required]
public ItemType ItemRule { get; set; }
public string Items { get; set; }
[Display(Name = "Price Rule"), Required]
public PriceType PriceRule { get; set; }
[Display(Name = "Value"), Column(TypeName = "MONEY")]
public decimal PriceValue { get; set; }
[Display(Name = "Exclusive?")]
public bool Exclude { get; set; }
}
public enum ItemType
{
Catalog,
Category,
Group,
Item
}
public enum PriceType
{
Catalog,
Price_A,
Price_B,
Price_C
}
A sample result from .net API:
[
{
$id: "1",
$type: "XYZ.CMgr.Models.CatalogRule, XYZ.CMgr",
ID: 1,
CatalogID: 501981,
ItemRule: 0,
Items: "198",
PriceRule: 1,
PriceValue: 0.5,
Exclude: false
},
{
$id: "2",
$type: "XYZ.CMgr.Models.CatalogRule, XYZ.CMgr",
ID: 2,
CatalogID: 501981,
ItemRule: 2,
Items: "9899",
PriceRule: 2,
PriceValue: 10.45,
Exclude: false
}
]
So in this example, I need to get Catalog for results[0].ItemRule & Price A for results[0].PriceRule. How can I accomplish this in BreezeJS??
This is easy to do in ASP.NET Web API, because it is an out-of-box feature in the default JSON serializer (Json.NET).
To see strings instead of enum numbers in JSON, just add an instance of StringEnumConverter to JSON serializer settings during app init:
var jsonFormatter = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
jsonFormatter.SerializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter());
UPDATE: Yep, you right, this is not help with Breeze.js. Ok, you can anyway do a little magic to make enums work like strings (while new version with fix is not released).
Create a custom ContextProvider which updates all integer enum values in metadata to strings. Here it is:
public class StringEnumEFContextProvider<T> : EFContextProvider<T>
where T : class, new()
{
protected override string BuildJsonMetadata()
{
XDocument xDoc;
if (Context is DbContext)
{
xDoc = GetCsdlFromDbContext(Context);
}
else
{
xDoc = GetCsdlFromObjectContext(Context);
}
var schemaNs = "http://schemas.microsoft.com/ado/2009/11/edm";
foreach (var enumType in xDoc.Descendants(XName.Get("EnumType", schemaNs)))
{
foreach (var member in enumType.Elements(XName.Get("Member", schemaNs)))
{
member.Attribute("Value").Value = member.Attribute("Name").Value;
}
}
return CsdlToJson(xDoc);
}
}
And use it instead of EFContextProvider in your Web API controllers:
private EFContextProvider<BreezeSampleContext> _contextProvider =
new StringEnumEFContextProvider<BreezeSampleContext>();
This works well for me with current Breeze.js version (1.1.3), although I haven't checked other scenarios, like validation...
UPDATE: To fix validation, change data type for enums in breeze.[min|debug].js, manually (DataType.fromEdmDataType function, dt = DataType.String; for enum) or replace default function during app init:
breeze.DataType.fromEdmDataType = function (typeName) {
var dt = null;
var parts = typeName.split(".");
if (parts.length > 1) {
var simpleName = parts[1];
if (simpleName === "image") {
// hack
dt = DataType.Byte;
} else if (parts.length == 2) {
dt = DataType.fromName(simpleName);
if (!dt) {
if (simpleName === "DateTimeOffset") {
dt = DataType.DateTime;
} else {
dt = DataType.Undefined;
}
}
} else {
// enum
dt = DataType.String; // THIS IS A FIX!
}
}
return dt;
};
Dirty, dirty hacks, I know... But that's the solution I found
There will be a new release out in the next few days where we "change" breeze's enum behavior ( i.e. break existing code with regards to enums). In the new release enums are serialized and queried by their .NET names instead of as integers. I will post back here when the new release is out.

Returning LINQ to Entities Query Result as JSON string

I'm attempting to construct a web service that allows for RESTful requests to return LINQ to Entities data as JSON string data. I have no problem executing a call to the database that returns one specific object:
public Product GetTicket(string s)
{
int id = Convert.ToInt32(s);
MWAEntities context = new MWAEntities();
var ticketEntity = (from p
in context.HD_TicketCurrentStatus
where p.Ticket_ID == id
select p).FirstOrDefault();
if (ticketEntity != null)
return TranslateTicketEntityToTicket(ticketEntity);
else
throw new Exception("Invalid Ticket ID");
/**
Product product = new Product();
product.TicketId = 1;
product.TicketDescription = "MyTest";
product.TicketOperator = "Chad Cross";
product.TicketStatus = "Work in Progress";
return product;
*/
}
private Product TranslateTicketEntityToTicket(
HD_TicketCurrentStatus ticketEntity)
{
Product ticket = new Product();
ticket.TicketId = ticketEntity.Ticket_ID;
ticket.TicketDescription = ticketEntity.F_PrivateMessage;
ticket.TicketStatus = ticketEntity.L_Status;
ticket.TicketOperator = ticketEntity.L_Technician;
return ticket;
}
Using curl, I get json data:
curl http://192.168.210.129:1111/ProductService/ticket/2
{"TicketDescription":"Firewall seems to be blocking her connection to www.rskco.com","TicketId":2,"TicketOperator":"Jeff","TicketStatus":"Completed"}
That being said, I have no idea how to get a string of JSON objects using the following query:
public List<MyTicket> GetMyTickets(string userId)
{
MWAEntities context = new MWAEntities();
/**
* List of statuses that I consider to be "open"
* */
string[] statusOpen = new string[] { "Work in Progress", "Assigned", "Unassigned" };
/**
* List of tickets with my userID
* */
var tickets = (from p
in context.HD_TicketCurrentStatus
where statusOpen.Contains(p.L_Status) & p.L_Technician == userId
select new MyTicket(p.Ticket_ID, p.Ticket_CrtdUser, p.F_PrivateMessage, p.Ticket_CrtdDate, p.L_Status));
return ???;
}
MyTicket is a type defined as follows:
[DataContract]
public class MyTicket
{
public MyTicket(int ticketId, string TicketCreator, string FirstPrivateMessage, DateTime TicketCreatedDate, string Status)
{
this.TicketId = ticketId;
this.TicketCreator = TicketCreator;
this.FirstPrivateMessage = FirstPrivateMessage;
this.TicketCreatedDate = TicketCreatedDate;
this.Status = Status;
}
[DataMember]
public int TicketId { get; set; }
[DataMember]
public string TicketCreator { get; set; }
[DataMember]
public string FirstPrivateMessage { get; set; }
[DataMember]
public DateTime TicketCreatedDate { get; set; }
[DataMember]
public string Status { get; set; }
//p.Ticket_CrtdUser, p.Ticket_CrtdDate, p.Ticket_ID, p.F_PrivateMessage
}
I would just like to get a list of JSON strings as output in order to parse using JS. I've tried using a foreach loop to parse "var" into a List of MyTicket objects, calling .ToList()), etc., to no avail.
I cannot change the backend (SQL 2005/2008), but I'm trying to use a standard HTML/JS client to consume a .NET 4.0 web service. Any help would be greatly appreciated. I've spent literally days searching and reading books (especially on O'Reilly's Safari site) and I have not found a reasonable solution :(.
use Json.NET: http://james.newtonking.com/pages/json-net.aspx
using Newtonsoft.Json;
var serializer = new JsonSerializer();
serializer.Serialize(Response.Output, tickets); // per your example
EDIT: Argh, the above is if you want to handle the serialization yourself.
In your example, change the return of the method from List to Ticket[] and do
return tickets.ToArray();
I wanted to add that I eventually got help to solve this. I'm not using business entities even though I'm using the Entity Framework. This may not be a wise decision, but I'm increasingly confused with Linq2SQL and Linq2EF. Here is the the code that made the above work:
public List<MyTicket> GetMyTickets(string userId)
{
MWAEntities context = new MWAEntities();
/**
* List of statuses that I consider to be "open"
* */
string[] statusOpen = new string[] { "Work in Progress", "Created"};
var tickets = (from p
in context.HD_TicketCurrentStatus
where statusOpen.Contains(p.L_Status) & p.L_Technician == userId
select new MyTicket{
TicketId = p.Ticket_ID,
TicketCreatedDate = p.Ticket_CrtdDate,
FirstPrivateMessage = p.F_PrivateMessage,
Status = p.L_Status,
TicketCreator = p.Ticket_CrtdUser
});
return tickets.ToList();
}

Resources