DotNetT2 Light_1200x303

Using a mocking tool to write the unit tests required for your existing C# app is an easy task with JustMock.

StackOverflow is probably the largest and best-known developer community, right? And here is a random question with 23K views (and it is not the only one regarding this delicate subject): 

Can unit testing be successfully added into an existing production project?
If so, how and is it worth it? 

Long story short—yes and it is totally worth it. Regarding the ‘how’—take your time and read on. 

If you happen to be in the exact same position and are asking yourself the above question—welcome to the right place! No worries, there is a cure. And you do not even have to climb too steep of a hill for it. 

I have already chosen my ‘victim’ for our little experiment. It is called ERP and is part of Telerik UI for WPF’s Sample Applications. You can check it out here and download its source code by following the steps from the Download Product Files article. Long story short, you need a Telerik account and the zip before the last from the following screenshot: 

Telerik Trial Account

I am glad that we cleared the above up, we can go on with the real deal now. Ready? I'm ready. 

Why Use a Mocking Tool? 

Writing a thorough set of unit tests is definitely time-consuming. Even a simple if statement with one line of code and a Boolean condition would require at least two tests to cover the possible outcomes (one for true, and one for false). Imagine what would be if the lines of code and the conditions were more than one. Yes, it would all escalate pretty fast. 😂 

Have you heard about mocking? 

Mocking is a process employed in unit testing to simulate external dependencies. 

Kurzgesagt (a.k.a. in English, in a nutshell), mocking is a concept in unit testing where real objects are substituted with fake objects that imitate the behavior of the real ones. It is done so that a test can focus on the code being tested and not on the behavior or state of external dependencies. 

Of course, these fake (or mock) objects can be created and maintained manually. Doing it all by yourself could cost you tons of time and be ultimately unproductive (and sometimes boring 🤫). Oh, and let's not forget the case in which your app code is so complex that you need to either do a major refactoring, or (even worse)—rewrite it completely from scratch.

That's why I would suggest use a mocking framework. Especially when talking about apps written without the slightest idea for covering with unit tests.

What is a mocking framework? 

Mocking frameworks are used to generate replacement objects like Stubs and Mocks. Mocking frameworks complement unit testing frameworks by isolating dependencies but are not substitutes for unit testing frameworks. By isolating the dependencies, they help the unit testing process and aid developers in writing more focused and concise unit tests. The tests also perform faster by truly isolating the system under test. 

What Is JustMock and Why Choose It? 

Currently, there are some free mocking frameworks on the market, yet my honest opinion is that they are simply insufficient. Most mocking frameworks have limitations as to what they can mock. The limitation comes from the way the mock object is created, which is through inheritance. The mock object can inherit only public APIs like virtual methods, abstract classes and interfaces. This functionality may be enough for your project as many companies have internal projects where all APIs can be public as they won’t be consumed by a third party. Yet, if your development team is dealing with internal, private logic, static calls or a dependency on a third-party library, then Telerik JustMock is a better suited solution. It helps you advance the unit testing of C# devs. 

Spending money for a complete mocking tool like JustMock enables developers to focus solely on testing the system under test and forget about the distracting mocking details. Mock objects are created automatically in memory when the tests are run based on the simple configuration in the unit test. There are no ‘physical’ mock objects that must be maintained as the project changes. 

Telerik JustMock is the fastest, most flexible, and complete mocking solution for crafting unit tests that support Blazor, ASP.NET Core, ASP.NET MVC, ASP.NET Web Forms, .NET Core, WPF, WinForms and the current preview of .NET 5. And it will definitely help you solve all potential problems before being busted by the QA. 🤓 Oh, yeah! 

With Telerik JustMock, any developer could start creating mocks, subs and fakes and use them in their tests. Wanna learn how JustMock makes unit tests more concise? Okay, let's dive right in. 

Unit Tests and JustMock—Where to Start? 

Let's first sum up the requirements of our experiment. We have: 

  • A real WPF in C# application (the ERP app)
  • Not a single unit test
  • No idea where to start 

I suggest we take a look at the ERP app for starters: 

Telerik UI For WPF ERP Sample App

The times I have seen or interacted with it can be counted on the fingers of a hand. But that should not bother me, or you (well, at least not a lot). 

Forgot to mention something about JustMock – it follows the Arrange-Act-Assert Pattern. The AAA Pattern makes a test look simpler and more structured by dividing it in three subsections, as explained below: 

  • Arrange – the section of the test where all required test objects and prerequisites are prepared
  • Act – the section where the actual work is performed
  • Assert – the section where all verifications of expectations and results are performed 

Having the JustMock extension installed, you are guaranteed a flying start. The project templates that come with it helped me create a test project in seconds. 

Now, I'm ready for unit testing! 

Edit / Remove Orders 

See the edit and delete buttons at the left below the Breadcrumb bar? I bet there is a Command related to both.

Noticed that the Orders item is initially selected? Surprisingly (or not) its DataContext is the OrdersViewModel. Back to the commands—yup, there they are: 

this.EditRecordCommand = new DelegateCommand(
    (o) =>
    {
        dialogFactory.TargetItemName = this.ItemName;
        dialogFactory.ShowEditDialog(this.ItemToEdit);
        this.Refresh();
    },
    (o) => this.ItemToEdit != null);
 
this.DeleteRecordCommand = new DelegateCommand(
    (o) =>
    {
        dialogFactory.TargetItemName = this.ItemName;
        if (dialogFactory.ShowDeleteDialog())
        {
            (this.ItemToEdit as ISavableObject).Delete();
            this.Refresh();
        }
    },
    (o) => this.ItemToEdit != null);

Let us see how the above can be covered with unit tests and write our first ones with Just Mock! The purpose of both tests—suppose there is a direct binding between the buttons and the commands. This way, we will be able to test the commands themselves. All dependencies (e.g., the ERPDialogFactory, the SalesOrderHeader, the CollectionView) will be mocked and the successful execution of the respective methods (e.g., the ShowEditDialog, ShowDeleteDialog, Refresh)—verified. Starting with the EditRecordCommand. 

[TestMethod]
public void OrdersViewModel_EditRecordCommandExecutedSuccessfully()
{
    //Arrange
    var dialogFactory = Mock.Create<ERPDialogFactory>();
    var salesOrderItem = Mock.Create<SalesOrderHeader>();
    var collectionView = Mock.Create<QueryableDataServiceCollectionView<SalesOrderHeader>>();
    Mock.Arrange(() => new ERPDialogFactory()).Returns(dialogFactory);
    Mock.ArrangeSet(() => dialogFactory.TargetItemName = "myItemName");
    Mock.Arrange(() => dialogFactory.ShowEditDialog(salesOrderItem)).DoNothing();
    Mock.Arrange(() => collectionView.HasChanges).Returns(true);
    Mock.Arrange(() => collectionView.RejectChanges()).InOrder();
    Mock.Arrange(() => collectionView.Refresh()).InOrder();
 
    //Act
    var viewModel = new OrdersViewModel();
    viewModel.SelectedItem = salesOrderItem;
    Mock.Arrange(() => viewModel.ItemName).Returns("myItemName");
    Mock.Arrange(() => viewModel.Items).Returns(collectionView);
    viewModel.EditRecordCommand.Execute(null);
 
    //Assert
    Mock.Assert(dialogFactory);
    Mock.AssertSet(() => dialogFactory.TargetItemName = "myItemName", Occurs.Once());
    Mock.Assert(salesOrderItem);
    Mock.Assert(collectionView);
}

Covering the DeleteRecordCommand with a unit test looks a lot like the EditRecordCommand's: 

[TestMethod]
public void OrdersViewModel_DeleteRecordCommandExecutedSuccessfully()
{
    //Arrange
    var dialogFactory = Mock.Create<ERPDialogFactory>();
    var salesOrderItem = Mock.Create<SalesOrderHeader>();
    var collectionView = Mock.Create<QueryableDataServiceCollectionView<SalesOrderHeader>>();
    Mock.Arrange(() => new ERPDialogFactory()).Returns(dialogFactory);
    Mock.ArrangeSet(() => dialogFactory.TargetItemName = "myItemName");
    Mock.Arrange(() => dialogFactory.ShowDeleteDialog()).Returns(true);
    Mock.Arrange(() => salesOrderItem.Delete()).DoNothing();
    Mock.Arrange(() => collectionView.HasChanges).Returns(true);
    Mock.Arrange(() => collectionView.RejectChanges()).InOrder();
    Mock.Arrange(() => collectionView.Refresh()).InOrder();
 
    //Act
    var viewModel = new OrdersViewModel();
    viewModel.SelectedItem = salesOrderItem;
    Mock.Arrange(() => viewModel.ItemName).Returns("myItemName");
    Mock.Arrange(() => viewModel.Items).Returns(collectionView);
    viewModel.DeleteRecordCommand.Execute(null);
 
    //Assert
    Mock.Assert(dialogFactory);
    Mock.AssertSet(() => dialogFactory.TargetItemName = "myItemName", Occurs.Once());
    Mock.Assert(salesOrderItem);
    Mock.Assert(collectionView);
}

Print These Orders 

What about the print button at the right below the Breadcrumb bar? That button:

<telerik:RadButton
    x:Name="Print"
    local:PrintExportHelper.PrintTarget="{Binding ElementName=gridView}"
    Style="{StaticResource GridNavigationButtonStyle}"
    Width="63">
    <!--
        Button content and tooltip here
    -->
</telerik:RadButton>

It has a PrintTarget set and I am guessing this is what I'm looking for. Let's peek at where this PrintTarget comes from and what it is supposed to do. This appears to be a dependency property, the setter of which will be called, and respectively—the PropertyChanged, when the above Binding is executed. This leads us to: 

private static void OnPrintTargetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var button = d as RadButton;
    var gridView = e.NewValue as RadGridView;
    if (button != null && gridView != null)
    {
        button.Command = new DelegateCommand(OnPrintCommandExecuted);
        button.CommandParameter = gridView;
    }
}
 
private static void OnPrintCommandExecuted(object obj)
{
    var gridView = obj as RadGridView;
    if (gridView != null)
    {
        var spreadsheet = new RadSpreadsheet();
        var window = new RadWindow() { Width = 0, Height = 0, Opacity = 0, Content = spreadsheet };
        window.Show();
        spreadsheet.Workbook = gridView.ExportToWorkbook();
        spreadsheet.Print(new PrintWhatSettings(ExportWhat.ActiveSheet, false));
        window.Close();
    }
}

Let's start from the button's XAML definition this time and test whether the binding is correctly resolved and respectively—clicking this button does its magic. 

[TestMethod]
public void PrintExportHelper_PrintButtonClickExecutesPrintCommand()
{
    //Arrange
    Mock.NonPublic.Arrange(typeof(PrintExportHelper), "OnPrintCommandExecuted", Arg.Expr.AnyObject);
 
    //Act
    var printButton = Mock.Create<RadButton>();
    var args = Mock.Create<DependencyPropertyChangedEventArgs>();
    var gridView = Mock.Create<RadGridView>();
    Mock.Arrange(() => args.NewValue).Returns(gridView);
    PrivateAccessor.ForType(typeof(PrintExportHelper)).CallMethod("OnPrintTargetChanged", printButton, args);
    printButton.Command.Execute(gridView);
 
    //Assert
    Mock.Assert(typeof(PrintExportHelper));
}

This unit test does not seem sufficiently stable enough. It only ensures that there is a print button and when it is clicked, the static method of the above helper class is called. But does it function properly, i.e., what exactly happens when the button's command is executed? Let us test: 

[TestMethod]
public void PrintExportHelper_PrintCommandExecutionSucceeded()
{
    //Arrange
    var gridView = Mock.Create<RadGridView>();
    Mock.NonPublic.Arrange(typeof(PrintExportHelper), "OnPrintCommandExecuted", gridView);
    var spreadsheet = Mock.Create<RadSpreadsheet>();
    var workbook = Mock.Create<Workbook>();
    var window = Mock.Create<RadWindow>();
    Mock.Arrange(() => window.Show()).IgnoreInstance().InOrder();
    Mock.Arrange(() => window.Close()).IgnoreInstance().InOrder();
    Mock.Arrange(() => gridView.ExportToWorkbook());
    Mock.Arrange(() => spreadsheet.Print(Arg.IsAny<PrintWhatSettings>(), null)).IgnoreInstance();
 
    //Act
    PrivateAccessor.ForType(typeof(PrintExportHelper)).CallMethod("OnPrintCommandExecuted", gridView);
 
    //Assert
    Mock.Assert(typeof(PrintExportHelper));
    Mock.Assert(gridView);
    Mock.Assert(window);
    Mock.Assert(spreadsheet);
    Mock.Assert(workbook);
}

Here, we need to arrange three more things (apart from those in the previous test)—the window, the spreadsheet and its workbook (these will do the magic of exporting the grid data into a spreadsheet's workbook). 

The act we are performing is calling the OnPrintCommandExecuted method with the mocked grid view. 

The assert phase ensures that all the above arrangements were made, this time including the ones regarding the grid, the spreadsheet and its workbook apart from the PrintExportHelper. 

This is the happy path of the print functionality. What about passing an item, different than the expected grid view—e.g., an empty string, to the print command? Let us cover that with a test—assuming we passed a fake argument, the print command execution is expected to fail, right? 

[TestMethod]
public void PrintExportHelper_PrintCommandExecutionFailed()
{
    //Arrange
    var gridView = Mock.Create<RadGridView>();
    Mock.NonPublic.Arrange(typeof(PrintExportHelper), "OnPrintCommandExecuted", gridView).OccursNever();
    var spreadsheet = Mock.Create<RadSpreadsheet>();
    var workbook = Mock.Create<Workbook>();
    var window = Mock.Create<RadWindow>(Constructor.NotMocked);
    Mock.Arrange(() => window.Show()).IgnoreInstance().InOrder().OccursNever();
    Mock.Arrange(() => window.Close()).IgnoreInstance().InOrder().OccursNever();
    Mock.Arrange(() => gridView.ExportToWorkbook()).OccursNever();
    Mock.Arrange(() => spreadsheet.Print(Arg.IsAny<PrintWhatSettings>(), null)).IgnoreInstance().OccursNever();
 
    //Act
    PrivateAccessor.ForType(typeof(PrintExportHelper)).CallMethod("OnPrintCommandExecuted", String.Empty);
 
    //Assert
    Mock.Assert(typeof(PrintExportHelper));
    Mock.Assert(gridView);
    Mock.Assert(window);
    Mock.Assert(spreadsheet);
    Mock.Assert(workbook);
}

Guess what, it did. Not the test. The command execution—we arranged that no invocations of the above methods have ever occurred when acting with an empty string instead of the expected grid view. 

Just Mock Tests Run Results

Well, seems like the export, delete and print functionalities work as expected. Good job! 

What about the last button of this button bar—the export? Well, I'm leaving this as your JustMock homework. 📚 

Try It Out 

If you are intrigued (hopefully you are 🤞), I'll be more than happy to hear your honest feedback in the comments. 

Whether you: 

  • Are new to Telerik JustMock – learn more about it via the product page. It comes with a 30-day free trial, giving you some time to explore the capabilities of JustMock.
  • Are already familiar with Telerik JustMock – the R1 2021 release is already available for download in your account.
  • Want to take advantage of Mihail Vladov's advice on writing user tests—download the Unit Testing eBook now. 

Regardless of the above ‘cases,’ don't be shy to:

 Try The Latest JustMock Now

You won't regret it.


Viktoria Grozdancheva
About the Author

Viktoria Grozdancheva

Viktoria Grozdancheva is a frontend developer, part of the Progress Telerik UI for WPF & Silverlight team in Sofia. She holds a bachelor's degree in Computer Systems and Technologies. In her spare time, Viktoria loves practicing (and constantly updating) her collection of art hobbies, playing sports and hanging out with friends.

Related Posts

Comments

Comments are disabled in preview mode.
;