Telerik blogs
JustMock is Ready to Rock with Even More Supported C# Features in R3 2018_870x220

If you have struggled with how to test a method that returns a reference, or the local function defined in a method, then this is the blog post you should read. Read on to see everything that's new in the Telerik JustMock R3 2018 release.

Ref Return Values and Ref Locals

If you have followed the development of C# language you couldn't miss the introduction of "ref return values and ref locals." Testing this feature in the code is often related to the word struggle. The R3 2018 release makes the testing as easy as writing several lines of code. Consider the following methods that should be tested:

internal class Foo
{
  private static int[] array = { 1, 2, 3, 4, 5, 6 };

  public ref int GetRefReturnInstanceWithArgs(ref int p)
  {
    ref int local = ref array[0];
    local += p;

    return ref local;
  }

  private static ref int GetRefReturnPrivateStaticWithArgs(ref int p)
  {
    ref int local = ref array[0];
    local += p;

    return ref local;
  }
}

One of the intriguing parts of testing this code is how a value considered ref return can be created and returned instead of the original value. JustMock introduces a dedicated delegate for handling such a scenario and a helper class LocalRef which simplifies its usage. Check the following code to see a test example of how the ref return value is created and used:

[TestMethod]
public void MockRefReturnInstanceMethodWithArgs()
{
  // Arrange
  int expectedValue = 12;
  var sut = Mock.Create<Foo>();
  LocalRefHandle<int> localRef = LocalRef.WithValue(expectedValue);
  Mock.Arrange(sut, s => s.GetRefReturnInstanceWithArgs(ref Arg.Ref(Arg.AnyInt).Value))
      .Returns(localRef.Handle)
      .OccursOnce();

  // Act
  int param = 10;
  ref int result = ref sut.GetRefReturnInstanceWithArgs(ref param);

  // Assert
  Mock.Assert(sut);
  Assert.Equal(expectedValue, result);
}

And what about when the method is private or even private static? It should be a lot harder to test it, right? Not at all.

We are following the already known approach of mocking non-public API with the Mock.NonPublic expectation. But for the sake of avoiding confusion about which exact arrange method in the non-public expectation should be used, we extracted the required logic in a separate interface named INonPublicRefReturnExpectation.

Check the following test example:

[TestMethod]
public void MockRefReturnPrivateStaticMethodWithArgs()
{
  // Arrange
  int expectedValue = 12;
  Mock.SetupStatic<Foo>();
  LocalRefHandle<int> localRef = LocalRef.WithValue(expectedValue);
  Mock.NonPublic.RefReturn.Arrange<Foo, int>("GetRefReturnPrivateStaticWithArgs", ArgExpr.Ref(1))
      .Returns(localRef.Handle)
      .OccursOnce();

  // Act
  var privateAccessor = Mock.NonPublic.MakeStaticPrivateAccessor(typeof(Foo));
  int param = 10;
  ref int res = ref privateAccessor.RefReturn.CallMethod<int>("GetRefReturnPrivateStaticWithArgs", Arg.Ref(param).Value);

  // Assert
  Mock.Assert<Foo>();
  Assert.Equal(expectedValue, res);
}

As I said, several lines of code for a test following the Arrange, Act, Assert (AAA) testing pattern and the struggle is over. If you need more information you could check out our documentation article on the subject.

Local Functions

Local Functions is another feature of the C# language that developers get excited to use when they first hear about it. But then they take a step back after stumbling over the question of "how to test a local function?" The reason is simple. Until now there was no effective and maintainable way of testing local functions.

Telerik JustMock is now the first tool that provides support for testing and mocking local functions in reliable manner. Now to the more practical part. How exactly I can write my tests? Consider the following class that should be tested:

internal class Foo
{
  public int GetResult()
  {
    return 100 + GetLocal();
    int GetLocal()
    {
      return 42;
    }
  }
}

To mock this simple local function, I would need information about the name of the class, the name of the owner method and the name of the local function. Here is what the test would look like:

[TestMethod]
public void TestBasicScenario()
{
  //Arrange
  var sut = Mock.Create<Foo>(Behavior.CallOriginal);
  Mock.Local.Function.Arrange<int>(sut, "GetResult", "GetLocal").DoNothing();

  //Act
  var result = sut.GetResult();

  //Assert
  Assert.AreEqual(100, result);
}

You can see that the mock is created with the call original behavior. This is required for the owner method GetResult to execute the original code. If you need more information about the supported behaviors, please check our help article on the subject. 

This was the most basic case, but what about if an overload that takes parameters and has a local function as well is added later to the code? Consider the following overload:

public int GetResult(int param)
{
  return param + 100 + GetLocal();
  int GetLocal()
  {
    return 200;
  }
}

Well in this case another test should be written for the second overload with providing information about the types of its parameters. Here is what the test would look like:

[TestMethod]
public void MockGetResultParams()
{
  //Arrange
  var sut = Mock.Create<Foo>(Behavior.CallOriginal);
  Type[] containingMethodParamTypes = new Type[] { typeof(int) };
  Mock.Local.Function.Arrange<int>(sut, "GetResult", containingMethodParamTypes, "GetLocal").Returns(42);

  //Act
  var resultParams = sut.GetResult(10);

  //Assert
  Assert.AreEqual(42, resultParams);
}

JustMock now supports also directly executing a local function. Simply use the Call method in the IFunctionExpectation interface. Consider the following class that should be tested:

internal class Foo
{
  private bool IsEven(int value)
  {
    bool isEven = (value % 2 == 0)? true: false;
    return isEven;
  }

  public void Method()
  {
    bool result = LocalFunction(10);
    bool LocalFunction(int value)
    {
      return IsEven(value);
    }
  }
}

And here is what the test would look like:

[TestMethod]
public void CallLocal()
{
  //Arrange
  var sut = Mock.Create<Foo>(Behavior.CallOriginal);
  Mock.NonPublic.Arrange<bool>(sut, "IsEven").Returns(false);

  //Act
  var result = Mock.Local.Function.Call(sut, "Method", "LocalFunction", 14);

  //Assert
  Assert.Equal(false, result);
}

If you're wondering, JustMock supports also local functions used in private and static methods and classes. For more information you could check our documentation article.

Mocking Non-Public Property Setters

If you have used some unpleasant workaround to mock a non-public property setter than I have good news for you. You can safely delete it. We have introduced the ArrangeSet method in the INonPublicExpectation interface accessible through the Mock class to help you test those private setters. Just take a look at the following test example to get a better understanding of the concept.

Here is the private property that would be tested:

public class Foo
{
  private int Index { get; set; }
}

And here is what the test should look like:

[TestMethod]
public void MockNonPublicPropArrangeSet()
{
  // Arrange
  int expectedValue = 20;
  var sut = Mock.Create<Foo>(Behavior.CallOriginal);
  var privateAccessor = Mock.NonPublic.MakePrivateAccessor(sut);
  Mock.NonPublic.ArrangeSet(sut, "Index", 12).DoInstead(() => privateAccessor.SetProperty("Index", expectedValue));

  // Act
  privateAccessor.SetProperty("Index", 12);
  int res = (int)privateAccessor.GetProperty("Index");

  // Assert
  Assert.Equal(expectedValue, res);
}

Named Parameters

Named parameters has been a feature of C# for a long time now and it is quite popular among developers. Therefore, a while back we introduced support for mocking instance methods accepting named parameters. But we hadn't implemented support for mocking static methods accepting named parameters. This is now done, and it is as simple as arranging a normal static method. Check the following test example:

Here is the class and the method that would be tested.

internal class Foo
{
  public static void StaticAction(int param1 = 0, int param2 = 0, int param3 = 0)
  {
    throw new NotImplementedException();
  }
}

And here is what the test should look like:

[TestMethod]
public void TestStaticMethodAcceptingNamedParameters()
{
  // Arrange
  Mock.SetupStatic<Foo>();
  Mock.Arrange<Foo>(() => Foo.StaticAction(param2: 2, param1: 3)).OccursOnce();

  // Act
  Foo.StaticAction(3, 2);

  // Assert
  Mock.Assert<Foo>();
}

Check Out the Latest Version and Share Your Feedback

Make sure to try the latest version of JustMock and get back to us with your feedback. It is already available for download in your account.

Not a JustMock customer? Feel free to download a free 30-day trial.

Start My JustMock Trial

Watch the R3 Release Webinars

To see all the latest changes and updates across our new release in action, please join us on the Telerik UI R3 2018 webinar, on October 2, 2018 at 11 a.m.

Save My Seat


Mihail Vladov
About the Author

Mihail Vladov

Mihail Vladov is a Software Engineering Manager at Progress. He has more than a decade of experience with software and product development and is passionate about good software design and quality code. Mihail helped develop the WPF controls suite and Document Processing libraries which are used by thousands of developers. Currently, he is leading the JustMock team. In his free time, he loves to travel and taste different foods. You can find Mihail on LinkedIn.

Related Posts

Comments

Comments are disabled in preview mode.