Moq: How to setup a method with tupel having type T as tupel element - moq

I am using Moq 4.18.1. I have to setup a mock for the following method signature:
Task AddMultiMessagesWithTransactionAsync<T>(List<(string queueName, T content, string messageId)> messageInfos, bool createQueue = false) where T : class;
The special thing is the generic type inside the tupel, which is at the first parameter. And I think there lies the problem. Other mock-setups in the same project are working fine. The mock looks like:
Mock<IServiceBusService> sbSrvMock2 = new();
var messageInfos = It.IsAny<List<(string queueName, It.IsAnyType content, string messageId)>>();
var createQueue = It.IsAny<bool>();
sbSrvMock2
.Setup(sb => sb.AddMultiMessagesWithTransactionAsync<It.IsAnyType>(messageInfos, createQueue))
.Callback(new InvocationAction((inv) =>
{
var p1 = inv.Arguments[0];
var p2 = inv.Arguments[1];
Console.WriteLine("I was here");
}));
The callback is never triggered! Do I have a problem with setting up the signature? Is it something with async?

Related

How do I apply an array values to Mongodb find() in ASP.net

I want to retrieve the specific data using an array-values, but I don't know how to deal with it.
URL is like http://localhost/api/data?sym=aa&bb&cc
DB documents are like:
{"symbol":"aa","price":1.1}
{"symbol":"bb","price":1.2}
{"symbol":"cc","price":1.3}
{"symbol":"dd","price":1.4}
{"symbol":"ee","price":1.5}
the expected result is:
[
{"symbol":"aa","price":1.1}
{"symbol":"bb","price":1.2}
{"symbol":"cc","price":1.3}
]
My code is:
[HttpGet()]
public IEnumerable<Data> Get(string sym)
{
symbol = sym.Split('&');
//connect to database and collections
var client = new MongoClient("mongodb+srv://.....");
var db = client.GetDatabase("...");
var _portf = db.GetCollection<Data>("...");
return _portf.Find(???).ToList();
}
??? is where I have failed to find a solution. or I am completely wrong with the find() method.
I really need your help. Thank you!
Find takes in a FilterDefinition object. For example, a common way of getting a document from MongoDB by its ID would be:
public T LoadRecordById<T>(string table, Guid id)
{
var collection = db.GetCollection<T>(table);
var filter = Builders<T>.Filter.Eq("Id", id);
return collection.Find(filter).First();
}
You can combine multiple FilterDefinition objects together using the Or method:
var filter1 = Builders<T>.Filter.Eq("symbol", symbol);
var filter2 = Builders<T>.Filter.Eq("symbol", symbol);
var filter3 = Builders<T>.Filter.Eq("symbol", symbol);
var filter = Builders<T>.Filter.Or(filter1, filter2, filter3);
Hope this helps (it does not hurt to be nice, does it, #Dharman?)
I've found a very promising way which works perfectly. Thanks to this video
rewrite the code"
[HttpGet()]
public IEnumerable<Data> Get(string sym)
{
var symlist = sym.Split('&');
//connect to database and collections
var client = new MongoClient("mongodb+srv://.....");
var db = client.GetDatabase("...");
var _portf = db.GetCollection<Data>("...");
-->var fitlerDefinition = Builders<Findata>.Filter.In(a => a.Symbol, symlist);
return _portf.Find(fitlerDefinition).ToList();
}

MemoryCache.Default.AddOrGetExisiting returns null although the key is in the cache

I am writing unit tests for my asp.net web API application and one of them is trying to verify that AddOrGetExisting is working correctly. According to the MSDN documentation, AddOrGetExisting returns an item if it's already saved, and if not it should write it into Cache.
The problem I am having is that if I add the key to MemoryCache object from an unit test, then call AddOrGetExisting, it will always return null and overwrite the value instead of returning the value that is already saved. I am verifying that the value is in the cache right before I call AddOrGetExisting(bool isIn evaluates to true).
Here is the code for my memory cache and the test method. Any help would be much appreciated:
public static class RequestCache
{
public static TEntity GetFromCache<TEntity>(string key, Func<TEntity> valueFactory) where TEntity : class
{
ObjectCache cache = MemoryCache.Default;
var newValue = new Lazy<TEntity>(valueFactory);
CacheItemPolicy policy = new CacheItemPolicy { AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(60) };
bool isIn = cache.Contains(key);
// Returns existing item or adds the new value if it doesn't exist
var value = cache.AddOrGetExisting(key, newValue, policy) as Lazy<TEntity>;
return (value ?? newValue).Value;
}
}
public string TestGetFromCache_Helper()
{
return "Test3and4Values";
}
[TestMethod]
public void TestGetFromCache_ShouldGetItem()
{
ObjectCache cache = MemoryCache.Default;
CacheItemPolicy policy = new CacheItemPolicy { AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(60) };
var cacheKey = "Test3";
var expectedValue = "Test3Value";
cache.AddOrGetExisting(cacheKey, expectedValue, policy);
var result = Models.RequestCache.GetFromCache(cacheKey,
() =>
{
return TestGetFromCache_Helper();
});
Assert.AreEqual(expectedValue, result);
}
The issue may be that you're passing a Lazy<TEntity> as newValue within RequestCache.GetFromCache but passing a string as expectedValue in the test method.
When running the test, the cache.Contains(key) confirms that there is a value stored for that key, which is true. However it is a string instead of a Lazy<TEntity>. Apparently AddOrGetExisting decides to overwrite the value in that case.
The fix for this particular scenario may be to adjust the expectedValue assignment in your test to something like this:
var expectedValue = new Lazy<string>(TestGetFromCache_Helper);
You'd also need to pull the value from the Lazy in the test's final equality comparison, for example:
Assert.AreEqual(expectedValue.Value, result);

Using Moq can you verify a method call with an anonymous type?

I'm trying to verify a method call using Moq, but I can't quite get the syntax right. Currently, I've got this as my verify:
repository.Verify(x => x.ExecuteNonQuery("fav_AddFavorites", new
{
fid = 123,
inputStr = "000456"
}), Times.Once());
The code compiles, but the test fails with the error:
Expected invocation on the mock once, but was 0 times:
x => x.ExecuteNonQuery("fav_AddFavorites", new <>f__AnonymousType0<Int32, String>(123, "000456"))
No setups configured.
Performed invocations:
IRepository.ExecuteNonQuery("fav_AddFavorites", { fid = 123, inputStr = 000456 })
How can I verify the method call and match the method parameters for an anonymous type?
UPDATE
To answer the questions:
I am trying to verify both that the method was called and that the parameters are correct.
The signature of the method I'm trying to verify is:
int ExecuteNonQuery(string query, object param = null);
The setup code is simply:
repository = new Mock<IRepository>();
UPDATE 2
It looks like this is a problem with Moq and how it handles anonymous types in .Net. The code posted by Paul Matovich runs fine, however, once the code and the test are in different assemblies the test fails.
This Passes
public class Class1
{
private Class2 _Class2;
public Class1(Class2 class2)
{
_Class2 = class2;
}
public void DoSomething(string s)
{
_Class2.ExecuteNonQuery(s, new { fid = 123, inputStr = "000456" });
}
}
public class Class2
{
public virtual void ExecuteNonQuery(string s, object o)
{
}
}
/// <summary>
///A test for ExecuteNonQuery
///</summary>
[TestMethod()]
public void ExecuteNonQueryTest()
{
string testString = "Hello";
var Class2Stub = new Mock<Class2>();
Class1 target = new Class1(Class2Stub.Object);
target.DoSomething(testString);
Class2Stub.Verify(x => x.ExecuteNonQuery(testString, It.Is<object>(o => o.Equals(new { fid = 123, inputStr = "000456" }))), Times.Once());
}
##Update##
That is strange, it doesn't work in different assemblies. Someone can give us the long definition about why the object.equals from different assemblies behaves differently, but for different assemblies, this will work, any variance in the object values will return a different hash code.
Class2Stub.Verify(x => x.ExecuteNonQuery(testString, It.Is<object>(o => o.GetHashCode() == (new { fid = 123, inputStr = "000456" }).GetHashCode())), Times.Once());
One option is to "verify" it in a Callback. Obviously this needs to be done at Setup time, e.g.:
aMock.Setup(x => x.Method(It.IsAny<object>())).Callback<object>(
(p1) =>
{
dynamic o = p1;
Assert.That(o.Name, Is.EqualTo("Bilbo"));
});
None of the answers are great when your test assembly is different than the system under test's assembly (really common). Here's my solution that uses JSON serialization and then strings comparison.
Test Helper Function:
using Newtonsoft.Json;
public static class VerifyHelper
{
public static bool AreEqualObjects(object expected, object actual)
{
var expectedJson = JsonConvert.SerializeObject(expected);
var actualJson = JsonConvert.SerializeObject(actual);
return expectedJson == actualJson;
}
}
Example System Under Test:
public void DoWork(string input)
{
var obj = new { Prop1 = input };
dependency.SomeDependencyFunction(obj);
}
Example Unit Test:
var expectedObject = new { Prop1 = "foo" };
sut.DoWork("foo");
dependency.Verify(x => x.SomeDependencyFunction(It.Is<object>(y => VerifyHelper.AreEqualObjects(expectedObject, y))), Times.Once());
This solution is really simple, and I think makes the unit test easier to understand as opposed to the other answers in this thread. However, because it using simple string comparison, the test's anonymous object has to be set up exactly the same as the system under the test's anonymous object. Ergo, let's say you only cared to verify the value of a single property, but your system under test sets additional properties on the anonymous object, your unit test will need to set all those other properties (and in the same exact order) for the helper function to return true.
I created a reusable method based on Pauls answer:
object ItIsAnonymousObject(object value)
{
return It.Is<object>(o => o.GetHashCode() == value.GetHashCode());
}
...
dependency.Verify(
x => x.SomeDependencyFunction(ItIsAnonymousObject(new { Prop1 = "foo" })),
Times.Once());
Also, this can be used for property name case-insensitive comparison:
protected object ItIsAnonymousObject(object value)
{
var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
return It.Is<object>(o => JsonSerializer.Serialize(o, options) == JsonSerializer.Serialize(value, options));
}

Verifying method with array passed by reference using Moq

Given the following interface
public interface ISomething {
void DoMany(string[] strs);
void DoManyRef(ref string[] strs);
}
I would like to verify that the DoManyRef method is called, and passed any string array as the strs parameter. The following test fails:
public void CanVerifyMethodsWithArrayRefParameter() {
var a = new Mock<ISomething>().Object;
var strs = new string[0];
a.DoManyRef(ref strs);
var other = It.IsAny<string[]>();
Mock.Get(a).Verify(t => t.DoManyRef(ref other));
}
While the following not requiring the array passed by reference passes:
public void CanVerifyMethodsWithArrayParameter() {
var a = new Mock<ISomething>().Object;
a.DoMany(new[] { "a", "b" });
Mock.Get(a).Verify(t => t.DoMany(It.IsAny<string[]>()));
}
I am not able to change the interface to eliminate the by reference requirement.
For verifying against ref arguments, you need to pass the actual instance into the verify call. This means your first test should appear as follows:
[Test]
public void CanVerifyMethodsWithArrayRefParameter()
{
var a = new Mock<ISomething>().Object;
var strs = new string[0];
a.DoManyRef(ref strs);
Mock.Get(a).Verify(t => t.DoManyRef(ref strs));
}
The final sentence of the question leads me to believe you might not be able to make that change, but that is what is required for the Verify call to succeed. Hope this helps.

Best way to typecast deserialised JSON

I think I've established that in as3corelib JSON.decode I have no choice but to deserialise to a plain old flex object.
var data:Object = JSON.decode(json);
If I then want to get the data contained in the object into another type I can't use type casting. I have to instantiate a new instance and add the properties manually.
var data:Object = JSON.decode(json);
var model:Model = new Model();
model.name = data.name;
model.notes = data.notes;
A pain and a bit ugly, but I'm guessing this is the price to be paid for going from untyped json to a flex type. My first question is whether my assumption is correct and there is no prettier way to create my model instance with the data contained within the json?
My second question, if so then before I write my own method to do this, is there anything inside the flex api that will take the data object and mixin it's values to my model instance?
Cheers,
Chris
the approach I've always used proved to be part of the AMF3 serialization mechanism in ActionScript.
have a look at IExternalizable and registerClassAlias.
now what I use is the following:
interface ISerializable {
public function getRawData():Object;
public function setRawData(param:Object):void;
}
function registerType(id:String, type:Class):void {
//implementation
}
function getTypeByID(id:String):Class {
//implementation
}
function getTypeID(type:Class):String {
//implementation
}
and to the decoder/encoder you register a class alias.
serialization of an object works as follows:
var raw:Object = model.getRawData();
raw[" type"] = getTypeID(model);
var encoded:String = JSON.encode(raw);
decoding works as follows:
var raw:Object = JSON.decode(raw);
var cl:Class = getTypeByID(raw[" type"]);
if (cl == null) throw new Error("no class registered for type: "+raw[" type"]);
delete raw[" type"];
var model:ISerializable = new cl();
model.setRawData(raw);
you will need to do this recursively on the whole deserialized JSON tree, starting at the leafs.
For cyclic reference, you'll need a trick.
I had an implementation of this somewhere, but I can't find it.
You can loop within the field of you json decoded object and assign them into your model:
function json2model(json:String):Model{
var data:Object = JSON.decode(json);
var m:Model=new Model();
for (var field:String in data) {
if (m.hasOwnProperty(field)) {
m[field] = data[field];
}
}
return m;
}
var model:Model=json2model(json)
or add a static function within your Model if you preffer:
public class Model {
//...
public static function fromJSon(json:String):Model {
var data:Object = JSON.decode(json);
var m:Model=new Model();
for (var field:String in data) {
if (m.hasOwnProperty(field)) {
m[field] = data[field];
}
}
return m;
}
}
}
var model:Model=Model.fromJSon(json);

Resources