I have to unit test a method which is querying DocumentDb using Linq and uses one of the predefined UserDefinedFunction "IS_DEFINED". When I try to unittest this method mocking the DocumentDb part, it throws an exception "This method should only be called within Linq expression to Invoke a User-defined function".
public void GetRequiredData()
{
var data = docDbClient.GetDataAsQueryable("some parameters").Where((bool)UserDefinedFunctionProvider.Invoke("IS_DEFINED"), somefield);
}
GetDataAsQueryable method get the data from documentDb which I mocked but UserDefinedFunctionProvider.Invoke throws an exception as it is not available in the unit testing scope.
How can I mock the UDF? Is there any other way I can unit test this method.
[UPDATE]
I tried using an Expression something like below
Expression<Func<object, bool>> expr = obj => (bool) UserDefinedFunctionProvider.Invoke("IS_DEFINED", obj);
var data = docDbClient.GetDataAsQueryable("some parameters").Where(expr.Compile()(someobject));
It throws an error "Nullable object must have a value"
What is the reason for this error and how to fix it?
At the moment you can't mock UDFs through UserDefinedFunctionProvider.
Related
public function __construct(RequestSchemaInterface $requestSchema)
{
$this->schema = $requestSchema->getSchema();
}
When I run phpspec for Builder then $this->schema is always null.
In normal call it sets schema.
I got let implemented
function let(RequestSchema $requestSchema)
{
$this->beConstructedWith($requestSchema);
}
How can I test methods of that class if they use $this->schema ?
Your let() method uses a stub to construct the object under test. While this is recommended, it is not required. You can create a real object of type RequestSchema and use it to construct the tested class:
function let()
{
$requestSchema = new RequestSchema();
$this->beConstructedWith($requestSchema);
}
Update:
Regarding the title of your question "How to make phpspec evaluate my constructor": the constructor is executed but, because you use a stub for $requestSchema, the call $requestSchema->getSchema() inside the constructor returns NULL.
You can prepare the stub to return something else when its method getSchema() is called.
Try this:
function let(RequestSchema $requestSchema)
{
// Prepare the stub
$requestSchema->getSchema()->willReturn('something');
// Construct the object under test using the prepare stub
$this->beConstructedWith($requestSchema);
// Verify the constructor initialized the object properties
$this->schema->shouldBe('something');
}
I am trying to mock a suggest response, however suggestionOption.Setup(x => x.Text).Returns("Hello") is throwing an exception:
An exception of type System.NotSupportedException occurred in
Moq.dll but was not handled in user code Additional information:
Invalid setup on a non-virtual (overridable in VB) member: x => x.Text
var searchSuggestResponseMock = new Mock<ISuggestResponse>();
var suggestionOption = new Mock<SuggestOption>();
suggestionOption.Setup(x => x.Text).Returns("Hello");
suggestionOption.Setup(x => x.Payload).Returns("{path:\"drugs/hello\"}");
var suggestion = new Mock<Suggest>();
suggestion.Setup(x => x.Options).Returns(new List<SuggestOption> { suggestionOption.Object });
searchSuggestResponseMock.Setup(x => x.Suggestions).Returns(new Dictionary<string, Suggest[]>()
{
{"suggest", new Suggest[] {suggestion.Object}},
});
var mock = new Mock<IConnector>();
mock.Setup(x => x.getClient()
.Suggest<Term>(Moq.It.IsAny<Func<SuggestDescriptor<Term>,
SuggestDescriptor<Term>>>())).Returns(searchSuggestResponseMock.Object);
_connector = mock.Object;
You can't mock non-virtual methods. As the error states:
Invalid setup on non-virtual member
Moq does its magic by acting as a proxy between your code and the real class. It does this by taking advantage of virtual methods. Without having a virtual method, Moq can't intercept the call.
Neither SuggestionOption, or Suggest are easily mockable, as they have non-virtual, internal set based properties, and do not implement any specific interface.
It looks like you are maybe mocking at too low a level. If you don't want to call Elastic to get your list of suggestions then have a method which just returns an array of strings (or your own custom Suggestion class) and mock that instead.
Or just call Elastic for real, as long as you are passing in sensible values which don't return thousands of suggestions.
(Or you could in theory create instances of Suggest, and set the internal properties via reflection, but this is not ideal obviously).
I have WebAPI implementation with method like this:
public IEnumerable<Device> GetAllDevices()
public Device GetDeviceById(int id)
Looks ok, it works when running in IIS or selfhosted. Returns JSON objects correctly.
However first method fails in my unit test where I attempt to use inmemory server.
System.InvalidOperationException : Cannot create and populate list type System.Linq.IQueryable`1[Test.Device].
This goes down to Newtonsoft.Json.Serialization assembly. An example of the test follow:
[Test]
public void GET_AskingForListOfDevices_GettingOk200WithListOfDevicesInJSON()
{
var client = new HttpClient(InMemoryServer);
HttpRequestMessage request = CreateRequest("api/devices", "application/json", HttpMethod.Get);
using (HttpResponseMessage response = client.SendAsync(request).Result)
{
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
Assert.NotNull(response.Content);
Assert.AreEqual("application/json", response.Content.Headers.ContentType.MediaType);
// next line throws exc
var content = response.Content.ReadAsAsync<IQueryable<Device>>().Result;
Assert.AreEqual(3, content.Count());
}
request.Dispose();
}
Any idea where to look?
UPDATE
The example below throws that error, however I found the solution to avoid it. Just by using IList<> instead of IQueryable<>. Still It does not answer me the question why it's working in Fiddler. Does it use the same trick?
I am running into same situation. IQueryable throws exception but if you use IEnumerable then it works.
I am using 'Xunit + TypeMock' to make test cases.
Whenever I am trying to call the follow method
protected abstract void UpdateObject(K response, ref int id)
from my test method, I get an exception.
I am calling this method from my test method like this :
int referenceID=0;
var passedResonse=new class();
Isolate.Invoke.Method(_FakeObject, "UpdateObject", passedResponse, ref referenceID);
But the method does not get called and give me error.
Kindly let me know, how can I call such methods (UpdateObject) from a test method.
Thanks
I am writing unittest for void method actually that method load the collection in
ViewData["CityList"] method is
public void PopulateCityCombo() {
IEnumerable<Cities> c= service.GetCities();
ViewData["CityList"] = c.Select(e => new Cities{ ID = e.ID, Name = e.Name});
}
now i do not know how to unit test using Moq since controller method is void and not returning data, can any one tell i will achive that.
On a side note, I would shy away from using ViewData within controller methods as per your example. The ViewData dictionary approach is fast and fairly easy to implement, however it can lead to typo's and errors that are not caught at compile time. An alternative would be to use the ViewModel pattern which allows you to use strongly-typed classes for the specific view you need to expose values or content within. Ultimately giving you type safe and compile time checking along with intellisense.
Switching to the ViewModel pattern would allow you to call the PopulateCityCombo() method from your controller to populate a ViewModel that in turn would passed to the corresponding view.
From there you would need to inject a mock service layer into your controllers constructor from your unit test.
// arrange
var mock = new Mock<servicelayer>();
mock.Setup(x=>x.GetCities()).Returns(expectedData);
var controller = new YourController(mock.Object);
// act
var result = controller.ControllerMethod() as ViewResult;
var resultData = (YourViewModel)result.ViewData.Model;
// assert
// Your assertions