Mocking in Csharp
Mocking in Csharp
3) .NET Framework
won't support .NET
Standard 2.1 or later
versions. For more
details, see the
announcement
of .NET 5+ TFMs.
if (successfullyCharged)
{
var shippingService = new ShippingService(); DepInjDemo
shippingService.Ship(address, city, name);
}
}
Dependency Injection (DI) 5
• From previous, we realize that we need to refactor our code into something more maintainable and
more secure. Turning a lot of the code into dependencies and replacing primitives with more
complex constructs is a good way to go
• The result could look something like below. We have turned both the PaymentService and
ShippingService into dependencies that we inject into the constructor
• We also see that all the primitives have been collected into the complex structures
IShippingAddress and IPaymentInfo. What remains is pure business logic
class TransactionController
{
private readonly IPaymentService _paymentService;
private readonly IShippingService _shippingService;
More examples
in the DI
project
Dependency Injection (DI) 7
• Dependency Graph
When you have a dependency it might itself rely on another dependency being resolved first and
so on and so forth. This means we get a hierarchy of dependencies that need to be resolved in
the right order for things to work out. We call this a Dependency Graph
• References
The Personnummer sample exam use both Autofac and Castle Windsor IoC containers
IamTimCorey (Design Patterns and Dependency Injection in C#)
https://www.youtube.com/watch?v=NnZZMkwI6KI
https://www.youtube.com/watch?v=mCUNrRtVVWY
Inversion of Control Containers and Dependency Injection pattern by Martin Fowler
https://www.martinfowler.com/articles/injection.html
Overview of Dependency Injection, DI MVC examples, DI in Controllers etc.
https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection
https://docs.microsoft.com/en-us/aspnet/core/mvc/views/dependency-injection
https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/dependency-injection
Overview of Dependency Injection namespace
https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection
Mocking a WebRequest
• The IWebRequest interface has in this case a Create() method that all classes have to implement
We can mock this method by using the Moq Setup() method
• When you want to mock a method with parameters you can work with the Moq.It.IsAny<type>()
option – used when argument value for a method call is not relevant
• In this example all string values are allowed
[Fact]
public void ShouldReturnContentStringWhenStatusCodeIsOk() LinkReader
{ LinkReaderTest
var resultContent = "<html><b>I am the test</b></html>";
var resultContentBytes = Encoding.ASCII.GetBytes(resultContent); (HtmlRetrieverTest.cs)
var moq = new Mock<IWebRequest>();
var moqHttpWebRequest = new Mock<HttpWebRequest>();
var moqHttpWebResponse = new Mock<HttpWebResponse>();
// Discards (from C# 7.0): https://docs.microsoft.com/en-us/dotnet/csharp/discards
moqHttpWebResponse.Setup(_ => _.StatusCode).Returns(HttpStatusCode.OK); // same as: x => x.StatusCode
moqHttpWebResponse.Setup(_ => _.GetResponseStream()).Returns(new MemoryStream(resultContentBytes));
moqHttpWebRequest.Setup(_ => _.GetResponse()).Returns(moqHttpWebResponse.Object);
Mock<IFoo> { CallBase = true }; var actual = cls.LoadPeople(); // mocked DB call
Mock<IFoo> Assert.True(actual != null);
Assert.Equal(expected.Count, actual.Count);
{ DefaultValue = DefaultValue.Mock }
for (int i = 0; i < expected.Count; i++)
MockRepository(MockBehavior.Strict) {
{ DefaultValue = DefaultValue.Mock }; Assert.Equal(expected[i].FirstName, actual[i].FirstName);
Assert.Equal(expected[i].LastName, actual[i].LastName);
}
}
} // gmi2j3/docs.and.code/YouTube/Mocking in C# Unit Tests
C# Mocking with Moq Channel9 - 1
UnitTesting.MOQExamples
• We can also send the created mock object to another class via DI (A_FirstExample.cs)
• No actual code exist in the implementation FakeRepo namespace MOQExamples.SystemsUnderTest;
• If the faked methods gets called they execute public interface IRepo
throw new NotImplementedException(); {
Customer Find(int id);
[Fact] void AddRecord(Customer customer);
public void Should_Mock_Function_With_Return_Value() }
{ public class Customer
// Arrange {
var id = 12; public virtual int Id { get; set; }
var name = "Fred Flinstone"; public virtual string Name { get; set; }
var customer = new Customer {Id = id, Name = name}; }
var mock = new Mock<IRepo>(); public class TestController
{
mock.Setup(x => x.Find(id)).Returns(customer);
public TestController(IRepo repo, ILogger logger = null)
{
// the injector (this class) register a service (customer) to a controller _repo = repo;
// and the interface define how a client may use the service _logger = logger;
// https://en.wikipedia.org/wiki/Dependency_injection }
var controller = new TestController(mock.Object); public Customer GetCustomer(int id)
{
// Act try {
var actual = controller.GetCustomer(id); _repo.AddRecord(new Customer());
// Assert return _repo.Find(id);
Assert.Same(customer, actual); } catch (Exception ex) { throw; }
Assert.Equal(id, actual.Id); }
Assert.Equal(name, actual.Name); }
} // docs.and.code/channel9.msdn.com
C# Mocking with Moq 4
• When you are using the verification from an mock instance by calling moq.Verify() it does
check if all set up methods are called
• mock.Verify() Verifies that all verifiable expectations have been met
• mock.VerifyAll() Verifies all expectations regardless of whether they have been flagged as
verifiable
[Test] Twitter
public void ReceiveMessageShouldInvokeItsClientToWriteTheMessage()
Twitter.Tests
{
// Arrange
var client = new Mock<IClient>();
client.Setup(c => c.WriteTweet(It.IsAny<string>()));
var tweet = new Tweet(client.Object);
// Assert
// (Mock.Verify) Verifies that the method is Invoked during the Test exactly 1 time
client.Verify(c => c.WriteTweet(It.IsAny<string>()), Times.Once,
"Tweet doesn't invoke its client to write the message");
}
C# Mocking with Moq Channel9 - 2
• Verifiable() Marks the expectation as verifiable, meaning that a call to
Moq.Mock.Verify() will check if this particular expectation was met, and
specifies a message for failures
[Fact] UnitTesting.MOQExamples
public void Should_Verify_Times_Executed()
{ (B_Verification.cs)
// Arrange
var id = 12;
var name = "Fred Flinstone";
var customer = new Customer { Id = id, Name = name };
var mock = new Mock<IRepo>();
Expression<Func<IRepo, Customer>> call = x => x.Find(id);
mock.Setup(call).Returns(customer).Verifiable("Method not called");
// Act
var controller = new TestController(mock.Object);
var actual1 = controller.GetCustomer(id);
//var actual2 = controller.GetCustomer(id);
// Assert
mock.Verify(call, Times.Once);
}
C# Mocking with Moq 5
• Multiple Mock objects and dependency injection
public interface IWriter
{ Twitter
private const string Message = "Test"; void WriteLine(string message); Twitter.Tests
}
[Test] public interface ITweetRepository
public void SendTweetToServerShouldSendTheMessageToItsServer() {
{ void SaveTweet(string content);
}
// Arrange
public class MicrowaveOven : IClient
var writer = new Mock<IWriter>(); {
var tweetRepo = new Mock<ITweetRepository>(); private IWriter writer;
tweetRepo.Setup(tr => tr.SaveTweet(It.IsAny<string>())); ITweetRepository tweetRepo;
var microwaveOven =
new MicrowaveOven(writer.Object, tweetRepo.Object); public MicrowaveOven(IWriter writer,
ITweetRepository tweetRepo)
{
// Act this.writer = writer;
microwaveOven.SendTweetToServer(Message); this.tweetRepo = tweetRepo;
}
// Assert
tweetRepo.Verify(tr => public void SendTweetToServer(string message) =>
tr.SaveTweet(It.Is<string>(s => s == Message)), this.tweetRepo.SaveTweet(message);
Times.Once,
public void WriteTweet(string message) =>
"Message is not sent to the server"); this.writer.WriteLine(message);
} }
[TestMethod]
public void TestDatabaseMocking()
C# {
int size = 5;
string sql = "select * from EmployeeTable";
Polymorphism and
PolymorphismTest
Mocking // Arrange
List<Employee> expectedEmployees = new List<Employee>();
for (int i = 0; i < size; i++)
{
with }
expectedEmployees.Add(new Employee() { Name = "Kalle", Hours = Utils.HOURS });
expectedEmployees.Add(new Contractor() { Name = "Pelle", Company = "HDA" });
// Assert
• Polymorphism for (int i = 0; i < expectedEmployees.Count; i++)
{
is an example Assert.AreEqual(expectedEmployees[i].Name, employees[i].Name);
Assert.AreEqual(expectedEmployees[i].Hours, employees[i].Hours);
dealing with }
mocking // Act - other way using virtual methods in a class, but the class could as well implement an interface
var mockUtil = new Mock<Utils>();
simple web mockUtil.Setup(_ => _.LoadEmployees(sql)).Returns(AssignData(size));
var barDb = new BarDb(mockUtil.Object);
access, virtual List<Employee> barDbEmployees = barDb.LoadEmployees(sql);
}
public interface IDataBase
{
Mocking // A class with virtual methods we mock, mocks must be virtual or interface
public class Utils
with
{
public const int HOURS = 40;
public virtual List<Employee> GetMockEmployees() { throw new NotImplementedException(); }
public virtual bool WriteEmployees(List<Employee> employees) { throw new NotImplementedException(); }
Moq 7 }
public virtual List<Employee> ReadEmployees() { throw new NotImplementedException(); }
public virtual List<Employee> LoadEmployees(string sql) { throw new NotImplementedException(); }
DB access) [Serializable]
public class Employee
{
public string Name;
public int Hours { get; set; }
// continues ...
NSubstitute 1
A friendly substitute for .NET mocking frameworks as Moq made by the NUnit guys
Install NuGet packages: NSubstitute and NSubstitute.Analyzers.CSharp
Good documentation and maybe a bit easier than Moq
[Test]
public void TestMethod1ReturnsEqual() https://nsubstitute.github.io/
{
// basic syntax for creating a substitute is
var calculator = Substitute.For<ICalculator>(); namespace NsubstituteDemo;
// tell our substitute to return a value for a call
calculator.Add(1, 2).Returns(3); public interface ICalculator
Assert.That(calculator.Add(1, 2), Is.EqualTo(3));
{
// check that our substitute received a call, and did not receive others // method
calculator.Add(1, 2);
calculator.Received().Add(1, 2); int Add(int a, int b);
calculator.DidNotReceive().Add(5, 7); // property
// If our Received() assertion fails, NSubstitute tries to give us some help
// as to what the problem might be string Mode { get; set; }
// event
// We can also work with properties using the Returns syntax we use for methods
calculator.Mode.Returns("DEC"); event EventHandler PoweringUp;
Assert.That(calculator.Mode, Is.EqualTo("DEC")); }
// or just stick with plain old property setters (for read/write properties):
calculator.Mode = "HEX";
Assert.That(calculator.Mode, Is.EqualTo("HEX")); NSubstituteDemo
}
NSubstitute 2
[Test]
public void TestMethod2ReturnsEqual()
{
var calculator = Substitute.For<ICalculator>();
// NSubstitute supports argument matching for setting return values and asserting a call was received:
calculator.Add(10, -5);
calculator.Received().Add(10, Arg.Any<int>());
calculator.Received().Add(10, Arg.Is<int>(x => x < 0));
// We can use argument matching as well as passing a function to Returns() to get some more behaviour out of our substitute
calculator.Add(Arg.Any<int>(), Arg.Any<int>()).Returns(x => (int)x[0] + (int)x[1]);
Assert.That(calculator.Add(5, 10), Is.EqualTo(15));
// Returns() can also be called with multiple arguments to set up a sequence of return values.
calculator.Mode.Returns("HEX", "DEC", "BIN");
Assert.That(calculator.Mode, Is.EqualTo("HEX"));
Assert.That(calculator.Mode, Is.EqualTo("DEC"));
Assert.That(calculator.Mode, Is.EqualTo("BIN"));
}
[Test]
public void TestMethod3EventWasRaised()
{
var calculator = Substitute.For<ICalculator>();
bool eventWasRaised = false; // we can raise events on our substitutes
calculator.PoweringUp += (sender, args) => eventWasRaised = true;
calculator.PoweringUp += Raise.Event();
Assert.That(eventWasRaised);
Console.WriteLine("TestMethod3EventWasRaised: " + eventWasRaised);
NSubstituteDemo
}
C# Mocking Code samples
• Examine the bundled example code
• DependencyInjection
• MockingDemo Start and End with Tim Corey
https://www.youtube.com/watch?v=DwbYxP-etMY
• Presentations-master from channel 9
• cs-code2
MoqDemo
LinkReader and LinkReaderTest
Polymorphism and PolymorphismTest
Twitter and TwitterTest
NSubstituteDemo
HelloFluentAssertions and HelloFluentAssertionsTest
OneDrive > gmi2j3 > lectures > code_csharp
A lot of code is also found in the gmi2j3 > docs.and.code > YouTube folder
Visual Studio Code Metrics
• Analyze > Calculate Code Metrics > ...
• Part of the Roslyn Analyzers packages which analyze your code for style,
quality and maintainability, design and other issues
https://github.com/dotnet/roslyn-analyzers
https://docs.microsoft.com/en-us/visualstudio/code-quality/how-to-generate-code-metrics-data
Code Metrics results
Maintainability Index - Calculates an index value between 0 and 100 that represents the relative ease of
maintaining the code. A high value means better maintainability. Color coded ratings can be used to quickly identify
trouble spots in your code. A green rating is between 20 and 100 and indicates that the code has good
maintainability. A yellow rating is between 10 and 19 and indicates that the code is moderately maintainable. A red
rating is a rating between 0 and 9 and indicates low maintainability.
Cyclomatic Complexity - Measures the structural complexity of the code. It is created by calculating the number
of different code paths in the flow of the program. A program that has complex control flow will require more tests to
achieve good code coverage and will be less maintainable.
Depth of Inheritance - Indicates the number of class definitions that extend to the root of the class hierarchy. The
deeper the hierarchy the more difficult it might be to understand where particular methods and fields are defined
or/and redefined.
Class Coupling - Measures the coupling to unique classes through parameters, local variables, return types,
method calls, generic or template instantiations, base classes, interface implementations, fields defined on external
types, and attribute decoration. Good software design dictates that types and methods should have high cohesion
and low coupling. High coupling indicates a design that is difficult to reuse and maintain because of its many
interdependencies on other types.
Lines of Code - Indicates the approximate number of lines in the code. The count is based on the IL (Intermediate
Language) code and is therefore not the exact number of lines in the source code file. A very high count might
indicate that a type or method is trying to do too much work and should be split up. It might also indicate that the
type or method might be hard to maintain.
https://docs.microsoft.com/en-us/visualstudio/code-quality/code-metrics-values
Lizard Code Metrics
• Lizard is an extensible Cyclomatic Complexity Analyzer for many
programming languages which can output statistics in html
cpp, java, csharp, javascript, python, objectivec, ruby, php, swift, scala, ...
• Measures
Cyclomatic Complexity (CCNumber)
LOC (Lines of code)
Token count (number of unique words in the code)
http://www.lizard.ws
If your project targets a DIFFERENT .NET implementation, for example, .NET Core, .NET Standard, or .NET Framework,
you must manually enable code analysis by setting the EnableNETAnalyzers property to true in your
MSBuild project (.csproj) file by setting the following properties:
1. EnableNETAnalyzers
<PropertyGroup>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
</PropertyGroup>
2. AnalysisLevel
<PropertyGroup>
<AnalysisLevel>latest</AnalysisLevel>
</PropertyGroup>
More about the Roslyn Analyzers 2
In .NET 5+, code style analysis is configured using a new file type called .editorConfig
1. Go to the project properties and click on Code Analysis and enable all
2. Install the EditorConfig NuGet package
3. Create the .editorConfig file
4. Issues and errors will show up in Error List tab
Source: https://www.c-sharpcorner.com/article/analyzing-code-for-issues-in-net-5/
https://www.youtube.com/watch?v=qv6ZflueASY
SonarQube
Docker
https://docs.sonarqube.org/latest/setup/get-started-2-minutes/
Docker (or Podman)
Docker is a set of Platform as a Service (PaaS) products that use OS-
level virtualization to deliver software in packages called containers
Containers are isolated from one another and bundle their own software,
libraries and configuration files; they can communicate with each other
through well-defined channels
Because all of the containers share the services of a single operating
system kernel, they use fewer resources than virtual machines
Docker benefits
Consistent and Isolated Environment. Cost-effectiveness with Fast
Deployment. Mobility – Ability to Run Anywhere. Repeatability and
Automation. Test, Roll Back and Deploy. Flexibility. Collaboration, Modularity
and Scaling
Docker components
Software, objects (container, image, service > swarms), registries
Tools – docker CLI
Docker cmd_xyz, docker-compose, docker swarm
Publish .NET+ apps via terminal
• If you want to run or distribute your .NET+ app as an console app or exe file
(without VS) you must publish / generate an .exe via the dotnet command
Since by default only a .dll file may be created because of the portable apps model
// in a console via the dotnet exe enter the command below to run the Polymorphism project
C:\dev_folder\Polymorphism>dotnet run Polymorphism
// in a console via the dotnet exe enter the commands below to generate an exe for the Polymorphism project
C:\dev_folder\Polymorphism>dotnet publish -c Debug -r win10-x64
C:\dev_folder\Polymorphism>dotnet publish -c Release -r win10-x64