Moq for an interface with action / function argument

I am trying to make fun of a server call and verify that the verified code is called the correct method. The code structure is as follows:

public interface IServerAdapter { void CallServer(Action<IServerExposingToClient> methodToCall, out bool serverCalled); object CallServer(Func<IServerExposingToClient, object> methodToCall, out bool serverCalled); } public interface IServerExposingToClient { Resource GetResource(string id); void AddResource(Resource resource); } 

The code I'm testing accesses the implementation of IServerAdapter and calls the IServerExposingToClient methods on the server. The reason for this is that we do not want to implement each method (there are quite a lot of them) on IServerExposingToClient in the class. Since this is then called to the proxy server, it works well in our code.

The method call on the server is as follows:

 _mainViewModel.ServerAdapter.CallServer(m => m.AddResource(resource), out serverCalled); 

Now the problem is testing and mocking. I need to claim that the method ( AddResource ) was called on the server. out serverCalled (problem 1) is to make sure that the call made it on the server, so that the logic will flow in the same way as for the caller.

When I use the following Moq setup, I can claim that some method was called on the server:

 Mock<IServerAdapter> serverAdapterMock = new Mock<IServerAdapter>(); bool serverCalled; bool someMethodCalled = false; serverAdapterMock.Setup(c => c.CallServer(It.IsAny<Action<IServerExposingToClient>>(), out serverCalled)).Callback(() => someMethodCalled = true); // assign serverAdapterMock.Object to some property my code will use // test code Assert.IsTrue(someMethodCalled, "Should have called method on server."); 

As the test says, I can say that some method was called on the server. The problem is that I do not know which method was called. In some methods, the logic that I want to test can take different paths depending on the conditions, and for some scenarios, several paths can lead to a server call. Because of this, I need to know which method was called, so I can have the correct statements in my test (problem 2).

The serverCalled variable must be configured to match the signature of the method call in the IServerAdapter wizard. I would also very much like to be able to set this variable inside some callback or whatever, which would allow the logic of the tested code to proceed as it should (problem 1). Due to how it works now, serverCalled will not be installed by installing mock.

The main problem is not knowing which method is being called against the server. I tried using Match to check the delegate method name, but not the cigar.

 serverAdapterMock.Setup(c => c.CallServer(Match.Create<Action<IServerExposingToClient>>( x => IsAddResource(x)), out serverCalled)).Callback(() => someMethodCalled = true); 

When IsAddResource is IsAddResource , the function does not refer to AddResource, only where it was created, and with what argument it is called.

Does anyone know how to check which method was called?

For another problem with out serverCalled you can argue that the void method may be bool instead and that the other method may return null if we do not have a connection to the server (the last argument would be ambiguous, since a null value could mean that the object does not exist , or the server is unavailable).

I would really like the suggestions for solving both problems.

Thank you in advance

+4
source share
1 answer

There is one problem:

As you have already indicated, a call back here would be ideal. Unfortunately, because your method signature has an out parameter that Moq cannot currently capture. There is a post in the Moq forums that looks like your problem. There is no indication that it will be considered.

If you are open to changing your method signature, consider dropping the out parameter - they still smell a bit. Everything will be much simpler if you just throw an exception when the server is unavailable. Getting out of them (for the pun) will open your Callback to deal with your second problem.

The second problem:

Consider changing your method signature as Expression <Action <IServerExposingToClient>. I understand there are many angle brackets, but the expression is syntactically equivalent to Action <T> (you do not have to change the call code) and will allow your callback to go through the tree of code expressions and get the name of your call method.

You can get the method name using something like:

 public string GetMethodName(Expression<Action<IServerExposingToClient>> exp) { return ((ExpressionMethodCall)exp.Body).Method.Name; } 

You now have enough arsenal to go after your layout. You can either write a callback that registers the names of the method calls, or you can write matches to help determine the behavior of the method calls.

For instance:

 [Test] public void WhenTheViewModelIsLoaded_TheSystem_ShouldRecordOneNewResource() { // arrange var serverAdapterMock = new Mock<IServerAdapter>(); var subject = new SubjectUnderTest( serverAdapterMock.Object ); // act subject.Initialize(); // assert serverAdapterMock.Verify( c => c.CallServer( IsAddResource() ), Times.Exactly(1)); } static Expression<Action<IServerExposedToClient>> IsAddResource() { return Match.Create<Expression<Action<IServerExposedToClient>>>( exp => GetMethodName(exp) == "AddResource"); } 
+6
source

Source: https://habr.com/ru/post/1341195/


All Articles