C# - Unit Test for Json Data - c#

Please how can I write a Unit Test for crud api returning Json
//Get all cli
[HttpGet]
public IHttpActionResult GetAllCli()
{
var data = db.cli.ToList();
return Json(data);
}
// Post method for GetAllCli
[HttpPost]
public IHttpActionResult Post()
{
var pu = new client
{
FirstName = first,
LastName = last,
Address = addre,
};
db.cli.Add(pu);
db.SaveChanges();
return Json(new { StatusCode = "Success" });
}
Wasn't sure of how to go forward with this
[TestMethod]
public void GetAll_ShouldReturnAllCli()
{
var contrller = new CliController();
var result = contrller.GetAllCli() as JsonResult;
//result is null after this line
//Is there a way to get result count of the json dat
Assert.AreEqual(5, result);
}
result is always null.
Is there a way to get the count result of the json dat

In Web API Json method returns generic JsonResult<T> (from System.Web.Http.Results) and not JsonResult (from System.Web.Mvc) that's why you get null during cast. In order to cast to generic type you should not use anonymous type but define a class for result
public class Result
{
public string StatusCode { get; set; }
}
Then your test will look like this
using System.Web.Http.Results;
//...
var contrller = new CliController();
var result = contrller.GetAllCli() as JsonResult<Result>;

Update your test method as below, if you are only stuck at getting a count add more description in your question to make it clear what you have and what you are trying to do
[TestMethod]
public void GetAll_ShouldReturnAllCli()
{
var contrller = new CliController();
var result = contrller.GetAllCli() as JsonResult;
var Originalresult = JsonHelper.GetJsonObjectRepresentation<IDictionary<string, object>>(result);
Assert.AreEqual(5, Originalresult.count());
}

Related

Complex parameter not getting to web api server

I am trying a put operation from my mvc project, to a web api. I have two parameters one an integer type the other one is a complex type each time I make
a call to the server
the simple type gets to the server while the complex type is null. It works fine from postman... Please I need to know what i'm doing wrong
Here is my model
//Same with client side
public class PaymentTypeVM
{
public int Id { get; set; }
public string Name { get; set; }
}
Here is my client side code
public static async Task<RequestResult> EditPaymentType<T>(int id, T model)
{
var content = new { Model = model };
var str = JsonConvert.SerializeObject(content);
var resp = await _client.PutAsync($"api/admin/editpaymenttype/{id}", new StringContent(str, Encoding.UTF8, "application/json"));
var txt = await resp.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<RequestResult>(txt);
}
Here is the server code
[HttpPut]
[Route("editpaymenttype/{id}")]
public async Task<RequestResult> EditPaymentType(int id, [FromBody]PaymentTypeVM model)
{
if (!ModelState.IsValid)
{
return RequestResult.FailureResult(Messages.InvalidEntry);
}
var pType = await db.PaymentTypes.FindAsync(id);
if (pType == null) return RequestResult.FailureResult(Messages.NotFound);
pType.Name = model.Name ?? pType.Name;
await db.SaveChangesAsync();
return RequestResult.SuccessResult($"Payment type {Messages.EditSuccessful}");
}
Please I need a simplified answer cos i'm a novice, Thanks in advance.
You should change it.
var content = new { Model = model };
var str = JsonConvert.SerializeObject(content);
to
var str = JsonConvert.SerializeObject(model);
Don't send the model as nested object.
Assuming that you call EditPaymentType like this: EditPaymentType<PaymentTypeVM>
Change this part in the client...
var content = new { Model = model };
var str = JsonConvert.SerializeObject(content);
to this...
var str = JsonConvert.SerializeObject(model);
You're currently sending it a serialized object that has a property of Model, with the value being your model, but then trying to map it to a parameter of type PaymentTypeVM when it's deserialized on the server.
If the types don't match then it can't deserialize the body contents into the parameter, and it ends up being null.
the HttpClient sends a parameter with this structure:
{
Model =
{
Id = 1,
Name = "Name"
}
}
while, the WebApi server expects a parameter like this:
{
Id = 1,
Name = "Name"
}

MOQ'd object returning null despite specifying .Returns

I am currently working with Moq to do some unit testing. I am running into an issue where I am specifying what my mocked object returns, but the actual call is returning null instead of what I am specifying in .Returns(...). I've reviewed other posts and one of the suggestions was to create the mock with MockBehavior.Strict- after doing this, I get a fairly verbose error as follows:
IMyRepository.Save(MvcIndividualAuth.Data.Models.DTO.MyTableDTO) invocation failed with mock behavior Strict.
All invocations on the mock must have a corresponding setup.
However, I am calling setup on the only method that my mocked object calls already. Please see code below:
My test:
MyService _myService;
Mock<IMyRepository> _myRepoMock;
[TestInitialize]
public void Setup()
{
_myRepoMock = new Mock<IMyRepository>();
_myService = new MyService(_myRepoMock.Object);
}
[TestMethod]
public void MyServiceSave()
{
//Arrange
var myDto = new MyTableDTO { Id = 1, Bar = 5, Foo = "Test" };
_myRepoMock.Setup(x => x.Save(myDto)).Returns(myDto);
//Act
var vm = _myService.Save(new MyTableViewModel(myDto));
//Assert
Assert.AreEqual(vm.Id, 1);
Assert.AreEqual(vm.Foo, "Test");
Assert.AreEqual(vm.Bar, 5);
Assert.AreEqual(vm.BarPlusFoo, "5 Test");
}
MyService.Save method:
public MyTableViewModel Save(MyTableViewModel viewModel)
{
var dto = MyTableViewModel.GetDto(viewModel);
var dbDto = _myRepo.Save(dto); //_myRepo is of type IMyRepository,
// this _myRepo.Save call is returning null
var vm = new MyTableViewModel(dbDto);
return vm;
}
Why is the mocked repo in my test not returning the value I specify in my .Returns(..) call? All help is appreciated.
EDIT: as requested, here is MyRepository.Save method and MyTableViewModel.GetDto():
MyRepository.Save:
public MyTableDTO Save(MyTableDTO dto)
{
try
{
var entity = new MyTable();
if (String.IsNullOrEmpty(dto.Foo))
{
throw new ArgumentException("MyTable requires Foo");
}
if (dto.Id == 0)
{
//added
entity.Update(dto);
_db.MyTables.Add(entity);
}
else
{
//modified
entity = _db.MyTables.Single(x => x.Id == dto.Id);
entity.Update(dto);
}
_db.SaveChanges();
return new MyTableDTO(entity);
}
catch (Exception)
{
throw;
}
}
MyTableViewModel.GetDto(..);
public static MyTableDTO GetDto(MyTableViewModel vm)
{
var dto = new MyTableDTO
{
Bar = vm.Bar,
Foo = vm.Foo,
Id = vm.Id
};
return dto;
}
You get null because GetDto() returns object different from myDto - references are different.
You can change your Setup() to return myDto:
_myRepoMock.Setup(x => x.Save(It.IsAny<MyTableDTO>())).Returns(myDto);
Or if you want to return object which was passed as a parameter:
_myRepoMock.Setup(x => x.Save(It.IsAny<MyTableDTO>())).Returns((MyTableDTO dto) => dto);
Or if you want to mock based on some properties:
_myRepoMock.Setup(x => x.Save(It.Is<MyTableDTO>(dto => dto.Id == 1))).Returns(myDto);
Or if you want to modify return result:
_myRepoMock.Setup(x => x.Save(It.IsAny<MyTableDTO>())).Returns((MyTableDTO dto) => { dto.Id = 2; return dto;});
You can also combine all approaches.
The MyTableDTO returned by GetDTO is a new MyTableDTO which is not the same as the rule in your Setup, because it has a different reference, hence there is no matching setup for Save.
Instead you can try something like:
_myRepo.Setup(s => s.Save(It.Is<MyTableDTO>(d => d.Equals(myDto))).Returns(myDto);
Or, if you are not concerned about the exact values passed to Save:
_myRepo.Setup(s => s.Save(It.IsAny<MyTableDTO>()).Returns(myDto);

How to return data in object format for web api?

I have to return data in json format but it says cannot implicitly convert type string to system.collection.generic.list(object).
[HttpGet]
public List<object> GetAllCompanies2()
{
List<object> myCo = DefCompany.AllDefCompany2;
// return myCo----------> works
string json = JsonConvert.SerializeObject(myCo);
return json; ------- > not works conversion error & i need this
}
I tried tostring() and many other ways but nothing worked. How can I convert string to object?
Here is my function code AllDefCompany2
public static List<object> AllDefCompany2
{
get
{
using (var db = new RPDBEntities())
{
return db.DefCompanies.Select(b => new
{
Id = b.Id,
CurrentCurrencyCode = b.CurrentCurrencyCode,
ShortName = b.ShortName,
FullName = b.FullName,
ContactPerson = b.ContactPerson,
Address1 = b.Address1,
CompanyCity = b.CompanyCity,
CompanyState = b.CompanyState,
CompanyCountry = b.CompanyCountry,
ZipPostCode = b.ZipPostCode,
TelArea = b.TelArea
}).ToList<object>();
}
}
}
this code helps me to solve both api and kendo problem
[HttpGet]
public List<object> GetAllCompanies2()
{
List<object> myCo = DefCompany.AllDefCompany2;
object json = JsonConvert.SerializeObject(myCo);
return json;
}
here is configuration settings
using System.Data.Entity;
namespace RpManticSolAPI
{
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
}
}
}
return JsonConvert.SerializeObject(myCo);
You can convert string to object, but what you are trying to do in the code shown is convert it to a List<object>. You can try calling AsEnumerable or ToList on the json variable.
But if what you want to do is return a string, why not change the return type of the method?
[HttpGet]
public string GetAllCompanies2()
{
List<object> myCo = DefCompany.AllDefCompany2;
// return myCo----------> works
string json = JsonConvert.SerializeObject(myCo);
return json; ------- > not works conversion error & i need this
}
Try this. Need to change function return type based on whether you return list of objects or string (in this case json)

Lose MongoDB ObjectId value when passing through Actions

In my MVC Controller, I have this code (after adding an object, I redirect user to edit that object):
[PrivilegeRequirement("DB_ADMIN")]
public ActionResult Add()
{
MongoDataContext dc = new MongoDataContext();
var model = new ModelObj();
dc.Models.Insert(model);
return this.RedirectToAction("Edit", new { pId = model.Id, });
}
[PrivilegeRequirement("DB_ADMIN")]
public ActionResult Edit(ObjectId? pId)
{
MongoDataContext dc = new MongoDataContext();
var model = dc.Models.FindOneById(pId);
if (model == null)
{
Session["error"] = "No model with this ID found.";
return this.RedirectToAction("");
}
return this.View(model);
}
However, pId is always null, making the FindOneById always return null. I have debugged and made sure that the Id had value when passing from Add Action. Moreover, I tried adding a testing parameter:
[PrivilegeRequirement("DB_ADMIN")]
public ActionResult Add()
{
MongoDataContext dc = new MongoDataContext();
var model = new ModelObj();
dc.Models.Insert(model);
return this.RedirectToAction("Edit", new { pId = model.Id, test = 10 });
}
[PrivilegeRequirement("DB_ADMIN")]
public ActionResult Edit(ObjectId? pId, int? test)
{
MongoDataContext dc = new MongoDataContext();
var model = dc.Models.FindOneById(pId);
if (model == null)
{
Session["error"] = "No model with this ID found.";
return this.RedirectToAction("");
}
return this.View(model);
}
When I debug, I received the test parameter in Edit Action with value of 10 correctly, but pId is null. Please tell me what I did wrong, and how to solve this problem?
I would suspect that the ObjectId is not serializing/deserializing correctly. Given that it doesn't make for a great WebAPI anyway, I generally use a string and convert within the method to an ObjectId via the Parse method (or use TryParse):
public ActionResult Edit(string id, int? test)
{
// might need some error handling here .... :)
var oId = ObjectId.Parse(id);
}
You can use ToString on the ObjectId to convert it to a string for calling:
var pId = model.Id.ToString();

Unit test won't "cover" simple get method. (c#)

I have a simple "Get" method. Ex:
public class Foo : IFoo
{
public Dictionary<string,string> GetSomething(string xyz)
{
var result = new Dictionary<string,string>
... Go to DB and return some key value pairs
return result;
}
}
I wrote a simple test that execute and passes successfully but I'm not getting code coverage on the method.
[TestMethod()]
public void GetSomething()
{
var target = new StubIFoo();
var expected = new Dictionary<string, string>
{
{"blahKey","blahValue"}
};
var results = target.GetSomethingString = s =>
{
var result = new Dictionary<string, string> {{"a", "b"}};
return result;
};
var actual = results("a");
CollectionAssert.AreEqual(expected,actual);
}
I also tried to target the class itself, which provides the coverage but doesn't return any results (ex: "var target = new StubFoo();")
Again, it successfully executes and passes but I'm not getting any coverage. Any pointers would be appreciated. Thanks.
Foo.GetSomething() has 0 code coverage, because you never call it in your test.
Instead, you call StubIFoo.GetSomething().
Change var target = new StubIFoo(); into var target = new Foo();, remove the code initializing StubIFoo and you will get some coverage.
Stubs are there to prevent you from using (and testing) the real class. But you must not use a stub of the class you are testing !
In your test you are not calling the method GetSomething, but instead are setting a value to the property GetSomethingString.
// Here is the problem. This:
var results = target.GetSomethingString = s =>
{
var result = new Dictionary<string, string> {{"a", "b"}};
return result;
};
// Is equal to this:
var lambda = s =>
{
var result = new Dictionary<string, string> {{"a", "b"}};
return result;
};
var results2 = target.GetSomethingString = lambda;
Here is general idea what you should do
public class Foo : IFoo
{
IDbAccess db;
// Pass the interface, do pass parameters to create it inside constructor
public Foo(IDbAccess db)
{
this.db = db;
}
public Dictionary<string,string> GetSomething(string xyz)
{
var result = new Dictionary<string,string>
// ... Go to DB and return some key value pairs
result.Add(db.MethodWhatever(xyz));
return result;
}
}
[TestMethod()]
public void GetSomething()
{
var dbMock = new DatabaseMock(); // This implements IDbAccess
var target = new Foo(dbMock);
var expected = new Dictionary<string, string>
{
{"blahKey","blahValue"}
};
// get something
var results = target.GetSomething("xyzstring");
// verify results
var actual = results.whatever;
CollectionAssert.AreEqual(expected,actual);
}

Categories