Helper method for testing JsonResult in Nunit - c#

Here is my controller that returns a JSON.
public JsonResult GetValues()
{
return Json(
new{
title = new {
text = "Hello World"
},
xAxis = new {
type = "List of countries"
labels = new {
rotation = 90
}
}
},JsonRequestBehavior.AllowGet);
}
And in my Nunit, i am testing as follows:
[Test]
public void TestGetValues()
{
var controller = new HelloWorldController();
var values = controller.GetValues() as JsonResult;
Assert.IsNotNull(data);
var title = values.Data.GetType().GetProperty("title")
.GetValue(values.Data,null);
var text = title.GetType().GetProperty("text").GetValue(title);
Assert.IsNotNull(text);
}
This works fine but i have to test several methods that has same properties which will require me to write same thing over and over again. How to write a helper method so that i can just pass in the controller and the property i want to test.
Something like this:
var checkText = GetJSonProperties(controllername, "data/title/text");
var checkXais = GetJSonProperties(controllernmae, "data/xAxis/Type");
How can i achieve this ?

I would just use a dynamic type.
var controller = new HelloWorldController();
dynamic values = controller.GetValues();
var title = (string)values.title;
Saves you writing helper methods, which themselves may need to be tested!

Related

How to write a unit test for a method which calls other services

I have a following method which is calling another service , but there is a some data manipulation before calling internal service. Please see below
public async Task<myObject> Save(string server,string username, myObject element)
{
string temp = element.Class + "_" + element.Description + "_" + username;
var saveData = new string[] { element.Name, temp};
var response = await datService.save(server, saveData);
var result = response.TomyObject(); // this is the extension method to convert response to myObject.
return result ;
}
What will be the best way to unit test?
I tried following but just want to make sure I am doing the "correct" way.
public async Task Save_Success()
{
//ARRANGE
var element = new myObject
{
Name = "Test",
Description = "Test Save",
Class = "test class"
};
string temp = element.Class+ "_" + element.Description + "_" + username;
var saveData = new string[] { element.Name, temp};
var response = new anotherObject
{
Name= "Test",
MyArray = new objArray
{
P0 = saveData[0],
P1 = saveData[1]
},
Error = ""
};
var datService = new Mock<IDataService>();
datService.Setup(x => x.Save(It.IsAny<string>(), It.IsAny<string[]>()).Returns(Task.FromResult(response));
var myClass = new MyClass(datService.Object);
//ACT
var result = await myClass.Save("testServer","testUser", element);
// ASSERT
Assert.AreEqual(response.MyArray.P0, result.Class);
}
Here is the extension method
public static myObject TomyObject(this anotherObject response)
{
var entity = new myObject();
entity.Name = response.Name;
if(response.MyArray!= null && response.MyArray.P1 != "")
{
string[] details = response.MyArray.P1.Split('_');
entity.Class = details[0];
entity.Description = details[1];
}
return entity;
}
Here is how you could test your extension method:
anotherObject response = new anotherObject
{
Name = "TestName",
MyArray = new objArray
{
P1 = "Val1_Val2"
}
};
var result = response.TomyObject();
Assert.Equal("TestName", result.Name);
Assert.Equal("Val1", result.Class);
Assert.Equal("Val2", result.Description);
The key is to have your unit tests only test one unit of work. If you want to test your extension method, write a test for it in isolation. Once you start including multiple units of work (i.e. the IDataService), you are actually testing a system and it becomes an integration test.
UPDATE:
On this line in your Save_Success test:
// ASSERT
Assert.AreEqual(response.MyArray.P0, result.Class);
You are actually testing something that is not the responsibility of the Save method (setting the Class property is actually the responsibility of your TomyObject, which could be tested separately).
To verify the Save method is doing what it's supposed to, you could do this:
// ASSERT
datService.Verify(x => x.Save(It.IsAny<string>(), It.IsAny<string[]>()), Times.Once);
That way, you're only testing that the Save method is doing what it's explicitly responsible for doing.

Test for parameter passed to NEST (elasticsearch)

I am using NEST to do elasticsearch queries.
public IReadOnlyCollection<IHit<Recommendation>> GetRecommendations(
RecommenderQueryFields shoulds,
RecommenderQueryFields musts,
RecommenderQueryFields mustNots)
{
var boolQuery = new BoolQuery();
boolQuery.Should = GetQueryContainers(shoulds);
boolQuery.Must = GetQueryContainers(musts);
boolQuery.MustNot = GetQueryContainers(mustNots);
var response = _elasticClient.Search<Recommendation>(s => s
.AllTypes().From(0).Size(10)
.Query(outerQuery => boolQuery));
return response.Hits;
}
I have logic in the GetQueryContainers method which I want to test.
Is there some way to check what has been passed to the ElasticClient in the boolQuery object?
I have tried the following stuff already, using NUnit and NSubstitute.
[Test]
public void Test1()
{
// Arrange
var searchResponse = Substitute.For<ISearchResponse<Recommendation>>();
searchResponse.Hits.Returns(new List<IHit<Recommendation>>());
var elasticClient = Substitute.For<IElasticClient>();
var sut = new Recommender(elasticClient);
// Act
sut.GetRecommendations(null, null, null);
// Assert
elasticClient
.Received(1)
.Search(Arg.Is<Func<SearchDescriptor<Recommendation>, ISearchRequest>>(x => true));
}
In the Arg.Is<[...]>(x => true) I would like to replace the true constant for some checks on boolQuery. But I do not know if it is possible or how it is done. Or is there a different way to do this?
TL;DR Use a derived QueryVisitor. See Edit2 below.
Found that the question has been answered already. It is not related to NEST, but to testing lambda expressions.
It is not possible: C# Moq Unit Testing with Lambda Expression or Func delegate
What can be done is testing the JSON request which will be sent to elasticsearch, but then you need the actual ElasticClient: ElasticSearch NEST 5.6.1 Query for unit test
What can be done is putting the logic in its own method/class. But then you write code simply for the sake of testing, which I'm not a fan of. Like:
public BoolQuery GetBoolQuery(RecommenderQueryFields shoulds, RecommenderQueryFields musts,
RecommenderQueryFields mustNots)
{
var boolQuery = new BoolQuery();
boolQuery.Should = GetQueryContainers(shoulds);
boolQuery.Must = GetQueryContainers(musts);
boolQuery.MustNot = GetQueryContainers(mustNots);
return boolQuery;
}
You are exposing a public method which you are not intending for use, only for testing.
But you can then assert on boolQuery like this:
[Test]
public void GetRecommendations_CallsElasticSearch()
{
// Arrange
var elasticClient = Substitute.For<IElasticClient>();
var sut = new Recommender(elasticClient);
// Act
var boolQuery = sut.GetBoolQuery(new RecommenderQueryFields{BlackListedFor = new List<string>{"asdf"}}, null, null);
// Assert
Assert.AreEqual(1, boolQuery.Should.Count());
}
In boolQuery.Should is a list of QueryContainer which are not testable because it is generated with lambdas aswell. While better than nothing, it is still not a clean way to test NEST.
Edit
#Russ Cam in the comment has mentioned the IQueryContainer and QueryVisitor
What I've got:
[Test]
public void test()
{
// Arrange
var fieldValue = "asdf";
var elasticClient = Substitute.For<IElasticClient>();
var sut = new Recommender(elasticClient);
// Act
var boolQuery = sut.GetBoolQuery(new RecommenderQueryFields { BlackListedFor = new List<string> { fieldValue } }, null, null);
// Assert
IQueryContainer qc = boolQuery.Should.First(); // Cast to IQueryContainer
Assert.AreEqual(fieldValue, qc.Match.Query); // Assert value
// Get "field name"
var queryVisitor = new QueryVisitor();
var prettyVisitor = new DslPrettyPrintVisitor(new ConnectionSettings(new InMemoryConnection()));
qc.Accept(queryVisitor);
qc.Accept(prettyVisitor);
Assert.AreEqual(0, queryVisitor.Depth);
Assert.AreEqual(VisitorScope.Query, queryVisitor.Scope);
Assert.AreEqual("query: match (field: blacklistedfor.keyword)\r\n", prettyVisitor.PrettyPrint);
}
The value of the field can be accessed via IQueryContainer.
I tried the QueryVisitor and the DslPrettyPrintVisitor. The first one doesn't provide any useful information. It has 0 depth and it is a Query? I already know that. With the second one I can assert some additional information, like the field name (blacklistedfor) and the suffix (keyword).
Not perfect to assert on the string representation, but better than nothing.
Edit2
#Russ Cam gave me a solution which I am really happy with. It uses a derived QueryVisitor:
public class MatchQueryVisitor : QueryVisitor
{
public string Field { get; private set; }
public string Value { get; private set; }
public override void Visit(IMatchQuery query)
{
var inferrer = new Inferrer(new ConnectionSettings(new InMemoryConnection()));
Field = inferrer.Field(query.Field);
Value = query.Query;
}
}
[Test]
public void test()
{
// Arrange
var fieldValue = "asdf";
var elasticClient = Substitute.For<IElasticClient>();
var sut = new Recommender(elasticClient);
// Act
var boolQuery = sut.GetBoolQuery(new RecommenderQueryFields { BlackListedFor = new List<string> { fieldValue } }, null,
null);
// Assert
IQueryContainer qc = boolQuery.Should.First();
var queryVisitor = new MatchQueryVisitor();
qc.Accept(queryVisitor);
Assert.AreEqual(fieldValue, queryVisitor.Value);
Assert.AreEqual("blacklistedfor.keyword", queryVisitor.Field);
}
So in MatchQueryVisitor, it gets the Field and Value, which are then asserted in the test method.

Checking the expected valued passed to a delegate using Rhino.Mocks

I am attempting to write a test case that will confirm that the value of a parameter passed into the method under test was used to invoke a delegate function that is passed as an argument to a method on a mocked service. The example below illustrates what I am doing:
The method under test:
public IList<IResultData> GetResultData(int id)
{
Func<IExternalInterface, List<ExternalData> getDataMethod = client => client.GetExternalData(id);
List<ExternalData> externalDataList = serviceClient.ExecuteService(getDataMethod, "GetExternalData");
var result = new List<ResultData>();
//Some code to convert externalDataList into an IList<IResultData>
return result;
}
The test method:
[TestMethod]
public void TestMethodCall()
{
var mockServiceClient = MockRepository.GenerateMock<IServiceClient>();
mockServiceClient.Expect(x => x.ExecuteService(
Arg<Func<IExternalInterface, List<ExternalData>>.Is.NotNull,
Arg<string>.Is.Equal("GetExternalData")));
var myClass = new MyClass(mockServiceClient);
var result = myClass.GetResultData(3);
//Some assertions that result is as expected.
}
Is there a way to assert that the function passed into the Execute method is being passed the id of 3 from the test method's call to GetResultData()? The service being mocked is in a library not under my control so I can't change it's signature.
The following pattern will allow you to assert the lambda:
[TestMethod]
public void TestMethod1()
{
var wasCalled = false;
var fakeService = MockRepository.GenerateStub<IExternalInterface>();
fakeService.Stub(x => x.GetExternalData(1))
.Return(new List<ExternalData>() {new ExternalData() {Id = 1}});
fakeService.Stub(service => service.ExecuteService(Arg<Func<IExternalInterface,
List<ExternalData>>>.Is.Anything, Arg<string>.Is.Anything))
.WhenCalled(invocation =>
{
wasCalled = true;
var func = (Func<IExternalInterface, List<ExternalData>>) invocation.Arguments[0];
var res = func(fakeService);
//
// Assert here the "res"
//
}).Return(null);
var target = new MyClass(fakeService);
target.GetResultData(1);
Assert. IsTrue(wasCalled);
}
However based you the code you've provided a better solution would be to use Do method as the following:
[TestMethod]
public void TestMethod1()
{
var fakeService = MockRepository.GenerateStub<IExternalInterface>();
fakeService.Stub(x => x.GetExternalData(1)).Return(new List<ExternalData>() {new ExternalData() {Id = 1}});
fakeService.Stub(service => service.ExecuteService(Arg<Func<IExternalInterface,
List<ExternalData>>>.Is.Anything, Arg<string>.Is.Anything))
.Do(new Func<Func<IExternalInterface, List<ExternalData>>, string, List<ExternalData>>((func, str)=>func(fakeService)));
var target = new MyClass(fakeService);
var result = target.GetResultData(1);
//
// Assert here the "result"
//
}

ODataComplexValue Actions and Casting

So I'm new to OData and I'm using Simple.OData.Client
So my code first looked like this :
var context = new ODataClient("http://localhost:51861/API/");
var test = context.For<Account>()
.Key("00010017")
.Action("Testing")
.Set(new Entry() { { "MyTest", New Test() { Item = "Hello World"} } })
.ExecuteAsScalarAsync<Test>()
.Result;
Leads to the following error:
"The value for parameter 'MyTest' is of type 'ODataExample.Model.MyTest'. WriteValue can only write null, ODataComplexValue, ODataEnumValue and primitive types that are not Stream type."
Ok, cool, so the exception above is informative and I can work with this by doing
ODataComplexValue MyTest = new ODataComplexValue();
ODataProperty myP = new ODataProperty();
myP.Name = "Item";
myP.Value = "Hello World";
myCustomer.TypeName = "ODataExample.Model.MyTest";
myCustomer.Properties = new[] { myP };
So now if I pass myTest into the .Set I get a working call to my OData server
.Set(new Entry() { { "MyTest", MyTest )
So Obviously I can create a ODataComplexValue with something like
var tt = new ODataComplexValue()
{
TypeName = t.GetType().FullName,
Properties = s.GetType().GetProperties().Select<PropertyInfo,ODataProperty>(x => new ODataProperty { Name = x.Name, Value = x.GetValue(t) })
};
The above works great and I an just create an extension method from that to have
.Set(new Entry() { { "MyTest", New Test() { Item = "Hello World"} } }.ToOData())
However, I can't help but feel I'm missing something, if the solution is this simple, why is Simple.OData.Client not just doing this for me? Is is there already an extension method or utility I should be using to get the same above result.
Just incase its required my webapi routing is as followed :
var function = builder.EntityType<Account>().Action("Testing");
function.Namespace = "Transaction";
function.Parameter<Test>("MyTest");
function.ReturnsFromEntitySet<Test>("Test");

Method that returning anonymous object

I have code parts like that:
var #object =
new
{
val = "SUCCESS",
stuff = new
{
stuff1 = model.Stuff1,
stuff2 = model.Stuff2
}
};
return Json(#object, JsonRequestBehavior.AllowGet);
var #object =
new
{
val = "SUCCESS"
};
return Json(#object, JsonRequestBehavior.AllowGet);
var #object =
new
{
val = "ERROR",
details = "Details"
};
return Json(#object, JsonRequestBehavior.AllowGet);
For me it is looking like kind of repetitive code that should be fixed.
I want to refactor that code so I can have something like that:
var #object = GetResult("SUCCESS", object myobj)
return Json(#object, JsonRequestBehavior.AllowGet);
What is the best practice of doing this?
Looks like you're interested in generating properties to anonymous types and assigning values to those properies in runtime.
There's a post here that shows you how to dynamically create classes but it seems like you will have to work pretty hard to get where you want.
Why not generate JSON strings from the different type of objects and the merge it to one JSON string?
string val = "SUCCESS";
var stuff = new
{
stuff1 = "some string",
stuff2 = "4324"
};
string json = new JavaScriptSerializer().Serialize(
new {val, stuff}
);
{"val":"SUCCESS","stuff":{"stuff1":"some string","stuff2":"4324"}}

Categories