According to StackOverflow, C# is one of the most-loved programming languages. And I completely understand that—it is powerful, easy to learn and consistently improving and developing. It is a living language. :)
The last couple of years, there were new features added to the languages, and the new versions keep coming up—C# 7, C# 8, C# 9.
As you know, we at Progress Telerik are proud that our products are always in sync with the latest things in the .NET world, and C# 9 and JustMock are no exception.
Most of the new features are easy to use in unit tests and in mocking, but there are some interesting things that I would like to show you so you can easily use the C# features in the unit testing:
To illustrate these, we will use a class Foo.
public
class
Foo
{
public
Foo()
{
this
.Bar = 10;
this
.DateTime =
new
DateTime(2021, 1, 1);
}
public
int
Bar {
get
; init; }
public
DateTime DateTime {
get
; init; }
public
bool
IsInRange(
int
i) =>
i
is
(>= 1 and <= 10) or (>= 100 and <= 200);
}
public
record Person
{
public
string
LastName {
get
; }
public
string
FirstName {
get
; }
public
Person(
string
first,
string
last) => (FirstName, LastName) = (first, last);
}
public
record Teacher : Person
{
public
string
Subject {
get
; }
public
Teacher(
string
first,
string
last,
string
sub)
:
base
(first, last) => Subject = sub;
}
Note: To run the examples, you need to download and install JM from here.
[TestMethod]
public
void
TestStaticLocal()
{
// Arrange
var sut =
new
Foo();
// Here is how to mock the static function
Mock.Local.Function.Arrange<
int
>(sut,
"MethodWithStaticLocal"
,
"Add"
, Arg.Expr.AnyInt, Arg.Expr.AnyInt).Returns(1);
// Act
var result = sut.MethodWithStaticLocal();
// Assert
Mock.Assert(sut);
Assert.AreNotEqual(12, result);
}
Starting with C# 8.0, you can create and consume streams asynchronously. A method that returns an asynchronous stream has three specifics:
In the example below, you can see an example of such a method along with an example of how you could mock it:
[TestMethod]
public
async Task TestAsyncEnumFromArray()
{
// Arrange
var expected =
new
int
[] { 10, 20, 30 };
Mock.Arrange(() => Foo.GetAsyncCollection())
.Returns(expected.GetEnumerator().ToAsyncEnumerable<
int
>());
// Act
var result = Foo.GetAsyncCollection();
// Assert
Mock.Assert<Foo>();
int
index = 0;
await
foreach
(var number
in
result)
{
Assert.AreEqual(expected[index++], number);
}
}
Init only setters provide consistent syntax to initialize members of an object. Property initializers make it clear which value is setting which property. The downside is that those properties must be settable. Starting with C# 9.0, you can create init
accessors instead of set
accessors for properties and indexers.
How do you mock it when you write a test? Using Mock.NonPublic.ArrangeSet method of JustMock.
[TestMethod]
public
void
TestInit()
{
// Arrange
var fooMock = Mock.Create<Foo>();
bool
properyInitCalled =
false
;
Mock.NonPublic.ArrangeSet(fooMock,
"Bar"
, 10)
.IgnoreInstance()
.DoInstead(() => properyInitCalled =
true
);
// Act
var foo =
new
Foo();
// Assert
Assert.IsTrue(properyInitCalled);
}
or
[TestMethod]
public
void
TestInit2()
{
// Arrange
var fooMock = Mock.Create<Foo>(Constructor.NotMocked);
dynamic fooMockWrapper = Mock.NonPublic.Wrap(fooMock);
Mock.NonPublic.Arrange(fooMockWrapper.Bar = 10)
.IgnoreInstance()
.MustBeCalled();
// Act
var foo =
new
Foo();
// Assert
Mock.NonPublic.Assert(fooMockWrapper.Bar = 10, Occurs.Once());
}
As the docs say, basically, you look at a given structure and, based on the way it looks, you identify it and you then can immediately use it. If you get a bag of fruit, you look down and immediately see the difference between the apples and the pears.
To show you how such functionality can be mocked with the InRange method, this is our sample of pattern matching and then the test below:
public
bool
IsInRange(
int
i) =>
i
is
(>= 1 and <= 10) or (>= 100 and <= 200);
...
[TestMethod]
public
void
Mock_PatternMatchingTest()
{
// Arrange
var foo = Mock.Create<Foo>(Behavior.CallOriginal);
Mock.Arrange(() => foo.IsInRange(Arg.AnyInt)).Returns(
true
);
// Act
var result20 = foo.IsInRange(20);
var result150 = foo.IsInRange(150);
//Assert
Assert.AreEqual(
true
, result20);
Assert.AreEqual(
true
, result150);
}
I know that reading code is not the same as running it, so to use it and play with the samples, follow the steps below:
For more tricks and trips on how to use the API of JustMock to write tests fast, read our Cheat Sheet.
If you are intrigued (hopefully you are 🤞), I’d be more than happy to hear your honest feedback in the comments.
Whether you:
Regardless of the above “cases,” don’t be shy to:
You won’t regret it.
Rossitza Fakalieva is a Technical Manager, Microsoft MVP in Developer Technologies and a Director of the Bulgarian chapter of the global Women Who Code organization. She previously worked on the Telerik engineering team and defines herself as .NET enthusiast. She loves to empower others to grow in their career and in the tech field—by teaching, by delivering courses and presentations, and as part of her daily job.