SOLIDWORKS C# API - Test Create Line Method

11 minute read

Objective

I want to:

  • Setup Test Model class for testing.
  • Test Create Line Method.
  • I will not explain each line, since they are already explained in previous articles.
  • We will continue from previous article ๐Ÿš€ Setup Test Project.

Demo Video

Watch the video below to learn how to Test Create Line Method.


Please note that there are no explanation in the video.
Explanation of each step and why we write code this way is given in this post.


Modify [MainWindowViewModel]

First, we need to make method we want to test and members we going to use in our test class make as public.

  • Public Member:
    • public string messageToShow;
  • Public Method:
    • public bool CreateLine(SketchSegment sketchSegment, double x1, double y1, double z1, SldWorks.SldWorks swApp, SketchManager sketchManager, double x2, double y2, double z2)
  • Modify Constructor:
    • Remove Below lines.
StartPointViewModel.Header = "Start Point Co-ordinates";
EndPointViewModel.Header = "End Point Co-ordinates";

All these changes we need to do in our MainWindowViewModel class.


Add [Private Fields]

Then, we need to add some Private Fields.

These fields are shown below.

#region Private Fields
private readonly Mock<IUnitConversionHelper> _mockConversionHelper;
private readonly Mock<IEventAggregator> _mockEventAggregator;
private readonly Mock<IContainerProvider> _mockContainer;
private readonly Mock<IPointViewModel> _mockStartPoint;
private readonly Mock<IPointViewModel> _mockEndPoint;
private readonly Mock<SldWorks.SldWorks> _mockSwApp;
private readonly Mock<ModelDoc2> _mockSwDoc;
private readonly Mock<SketchManager> _mockSketchManager;
private readonly Mock<ModelDocExtension> _mockModelDocExtension;
private readonly Mock<SketchSegment> _mockSketchSegment;

private readonly MainWindowViewModel _viewModel;
#endregion

Please see below ๐Ÿ‘‡๐Ÿป image for reference.

1-add-private-fields

In above code sample, we create a โ€œPrivate Fieldsโ€ region.

Inside this region we create some Mock properties and a field for MainWindowViewModel class.

This viewmodel field will allow us to test different methods.

These Mock object will help us to mock the dependencies.

Understand Mock Object

In this section, I will explain a Mock object/field.

private readonly Mock<SldWorks.SldWorks> _mockSwApp;
  • private: This means that only MainWindowViewModelTests class can use it; no one else is allowed.
  • readonly: This means that once we set this field, we cannot change or replace it. We can only use it as it is.
  • Mock<SldWorks.SldWorks> : โ€œMockโ€ refers to a simulated version of SldWorks.SldWorks, designed to mimic its behavior without being the actual software.
  • _mockSwApp: This is the name we gave our variable.

Similarly, we can understand other Mock fields through same analogy.


Understand [MainWindowViewModel] Field

private readonly MainWindowViewModel _viewModel;
  • private:
    • This means that the _viewModel can only be accessed and used within the MainWindowViewModelTests class.
    • No other part of the program can see or change it.
  • readonly:
    • This indicates that once _viewModel is set, it cannot be changed or reassigned to something else.
    • You can still use it, but you canโ€™t replace it with a different MainWindowViewModel later on.
  • MainWindowViewModel:
    • This is the type of the variable.
    • It suggests that _viewModel is a specific kind of object that contains the logic and data for the main window of an application.
  • _viewModel:
    • This is the name of the variable.
    • The underscore at the beginning is a common convention in programming to indicate that this is a private variable.

Add [Constructor]

Now we need to add a Default Constructor and set up the Mock object fields.

In this section, we will:

  • Create a region
  • Make a Default Constructor

In this constructor, we will:

  • Set up the mock object fields

We also use the Mock objects to set up our MainWindowViewModel field.

This will show us how we can use Mock objects to handle dependencies.

Please see below ๐Ÿ‘‡๐Ÿป code sample of Constructor.

#region Constructor

public MainWindowViewModelTests()
{
    _mockConversionHelper = new Mock<IUnitConversionHelper>();
    _mockEventAggregator = new Mock<IEventAggregator>();
    _mockContainer = new Mock<IContainerProvider>();
    _mockStartPoint = new Mock<IPointViewModel>();
    _mockEndPoint = new Mock<IPointViewModel>();
    _mockSwApp = new Mock<SldWorks.SldWorks>();
    _mockSwDoc = new Mock<ModelDoc2>();
    _mockSketchManager = new Mock<SketchManager>();
    _mockModelDocExtension = new Mock<ModelDocExtension>();
    _mockSketchSegment = new Mock<SketchSegment>();

    _viewModel = new MainWindowViewModel(_mockEventAggregator.Object, 
        _mockContainer.Object, _mockConversionHelper.Object);

    _viewModel.StartPointViewModel = _mockStartPoint.Object;
    _viewModel.EndPointViewModel = _mockEndPoint.Object;
} 
#endregion

Please see below ๐Ÿ‘‡๐Ÿป image for reference.

2-add-default-constructor


Set up Mock Fields

In the code below, we set up Mock type fields.

_mockConversionHelper = new Mock<IUnitConversionHelper>();
_mockEventAggregator = new Mock<IEventAggregator>();
_mockContainer = new Mock<IContainerProvider>();
_mockStartPoint = new Mock<IPointViewModel>();
_mockEndPoint = new Mock<IPointViewModel>();
_mockSwApp = new Mock<SldWorks.SldWorks>();
_mockSwDoc = new Mock<ModelDoc2>();
_mockSketchManager = new Mock<SketchManager>();
_mockModelDocExtension = new Mock<ModelDocExtension>();
_mockSketchSegment = new Mock<SketchSegment>();

Set up [MainWindowViewModel] Field

_viewModel = new MainWindowViewModel(_mockEventAggregator.Object, 
    _mockContainer.Object, _mockConversionHelper.Object);

ViewModel Initialization : In above code,

  • A new instance of MainWindowViewModel is created.
  • Dependencies injected into the constructor:
    • _mockEventAggregator.Object
    • _mockContainer.Object
    • _mockConversionHelper.Object

_mockEventAggregator.Object refers to an instance of a mock object created using a mocking framework. This resolve the dependency for creating instance.
_mockContainer.Object is similar object, we use to resolve another dependency.
_mockConversionHelper.Object is similar object, we use to resolve last dependency.
We need to resolve these dependencies otherwise we can not create the instance of MainWindowViewModel.

_viewModel.StartPointViewModel = _mockStartPoint.Object;
_viewModel.EndPointViewModel = _mockEndPoint.Object;

ViewModel Property Assignments : In above code we set,

  • StartPointViewModel property of _viewModel variable is assigned to _mockStartPoint.Object mock object created using a mocking framework.
  • EndPointViewModel property of _viewModel variable is set to _mockEndPoint.Object mock object created using a mocking framework.

Add Test Cases

Now we set up Test cases for below ๐Ÿ‘‡๐Ÿป CreateLine method of _viewModel variable.

public bool CreateLine(SketchSegment sketchSegment, double x1, double y1, double z1, SldWorks.SldWorks swApp, SketchManager swSketchManager, double x2, double y2, double z2)
{
    sketchSegment = swSketchManager.CreateLine(x1, y1, z1, x2, y2, z2);

    if (sketchSegment == null)
    {
        messageToShow = "Failed to Create Sketch line.";
        swApp.CloseAllDocuments(true);
        swApp.ExitApp();
        return false;
    }

    return true;
}

To test CreateLine method, we need 2 test cases.

  1. TestCase 1 : When Line Creation Fails Returns False
  2. TestCase 2 : When Line Creation Succeeds Returns False

Before we add test cases, we will create a region called โ€œTest Method [CreateLine]โ€.

This will help organize our code properly.


Add [TestCase 1]

In this section, we set up TestCase 1.

Please see below ๐Ÿ‘‡๐Ÿป code sample for set up.

[Fact]
public void CreateLine_ReturnsFalse_WhenLineCreationFails()
{
  // Arrange
  SketchSegment sketchSegment = null;
  _mockSketchManager.Setup(sm => sm.CreateLine(It.IsAny<double>(), It.IsAny<double>(), It.IsAny<double>(), It.IsAny<double>(), It.IsAny<double>(), It.IsAny<double>()))
                    .Returns((SketchSegment)null);

  // Act
  bool result = _viewModel.CreateLine(sketchSegment, 0, 0, 0, _mockSwApp.Object, _mockSketchManager.Object, 10, 10, 0);

  // Assert
  Assert.False(result);
  Assert.Equal("Failed to Create Sketch line.", _viewModel.messageToShow);
  _mockSwApp.Verify(app => app.CloseAllDocuments(true), Times.Once);
  _mockSwApp.Verify(app => app.ExitApp(), Times.Once);
}

Please see below ๐Ÿ‘‡๐Ÿป image for reference.

3-add-test-1-to-test-class

Explanation of above CreateLine_ReturnsFalse_WhenLineCreationFails is give below.

[Fact]
public void CreateLine_ReturnsFalse_WhenLineCreationFails()
{

}
  • [Fact] :
    • This is a test attribute.
    • This attribute shows that this method is a test case that the xUnit test runner recognizes.
  • public :
    • This means that the CreateLine_ReturnsFalse_WhenLineCreationFails method can be accessed from anywhere.
    • This is important, because xUnit test runner is external agent.
    • xUnit test runner need to have accessed to this CreateLine_ReturnsFalse_WhenLineCreationFails method.
    • Because of this requirment we need to give public accessor.
  • void :
    • This is the return type of CreateLine_ReturnsFalse_WhenLineCreationFails method.
    • Generally we donโ€™t return anything from test method.
    • Because of this we return void means we are not returning anything.
  • CreateLine_ReturnsFalse_WhenLineCreationFails
    • This is the name of method.
    • This name is created in 3 different parts and combined with underscore โ€œ_โ€œ.
    • Different parts are explained below ๐Ÿ‘‡๐Ÿป:
      • Part 1: Name of method we are testing.
      • Part 2: Return value we are expecting.
      • Part 3: Condition for which we are testing the method.
SketchSegment sketchSegment = null;
  • SketchSegment:
    • This is type of object we want to create.
  • sketchSegment:
    • This is name of object we want to create.
  • null:
    • This is the value we are assigning to sketchSegment variable.
_mockSketchManager.Setup(sm => sm.CreateLine(It.IsAny<double>(), It.IsAny<double>(), It.IsAny<double>(), It.IsAny<double>(), It.IsAny<double>(), It.IsAny<double>()))
                  .Returns((SketchSegment)null);
  • _mockSketchManager:
    • This is mocking object for SketchManager object.
  • _mockSketchManager.Setup():
    • We are using the Setup() method from _mockSketchManager object.
    • This is important and most basic one you should learn.
    • This Setup() method allow us to setup the behavior of object it is mocking and its members/methods.
      • Please follow me and you will be able to understand how we setup the child members/methods.
  • Setup(sm => sm.CreateLine(It.IsAny<double>(), It.IsAny<double>(), It.IsAny<double>(), It.IsAny<double>(), It.IsAny<double>(), It.IsAny<double>()))
    • sm is object we are mocking.
    • sm represent SketchManager.
    • From this sm object we will setup CreateLine method.
    • This method takes 6 double parameters.
    • We are defining that all 6 parameters will take any double value.
  • Returns((SketchSegment)null)
    • Here are setting up return value of CreateLine method.
    • Above we are saying, whenever CreateLine method called, return null.
    • Since CreateLine method return SketchSegment type hence we need to cast this also while setting up return value.
// Act
bool result = _viewModel.CreateLine(sketchSegment, 0, 0, 0, _mockSwApp.Object, _mockSketchManager.Object, 10, 10, 0);

In above code, we are calling CreateLine method of _viewModel variable and store the return value into result variable.

  • _viewModel:
    • ViewModel variable whose method we want to test.
  • CreateLine:
    • Method we want to test.
  • CreateLine(sketchSegment, 0, 0, 0, _mockSwApp.Object, _mockSketchManager.Object, 10, 10, 0)
    • Calling CreateLine method and passing parameters to method.
    • sketchSegment: Previously created variable.
    • 0, 0, 0: X1, Y1, Z1 co-ordinate of start point.
    • _mockSwApp.Object: SldWorks object from _mockSwApp variable.
    • _mockSketchManager.Object: SketchManager object from _mockSketchManager variable.
    • 10, 10, 0: X2, Y2, Z2 co-ordinate of end point.
// Assert
Assert.False(result);
Assert.Equal("Failed to Create Sketch line.", _viewModel.messageToShow);
_mockSwApp.Verify(app => app.CloseAllDocuments(true), Times.Once);
_mockSwApp.Verify(app => app.ExitApp(), Times.Once);
  • Assert.False(result);:
    • We are checking value of result variable is false.
    • If return value is false then our asseertion is true.
  • Assert.Equal("Failed to Create Sketch line.", _viewModel.messageToShow);
    • Similar to previous line, here we are checking value of _viewModel.messageToShow is equal to Failed to Create Sketch line.
    • If both value are same then our asseertion is true.
  • _mockSwApp.Verify(app => app.CloseAllDocuments(true), Times.Once);:
    • Here we are verifying CloseAllDocuments() method is called 1 time only.
    • We need to do this to make sure our code did not run too much.
  • _mockSwApp.Verify(app => app.ExitApp(), Times.Once);:
    • Here we are verifying ExitApp() method is called 1 time only.
    • We need to do this to make sure our code did not run too much.

Add [TestCase 2]

In this section, we set up TestCase 2.

Please see below ๐Ÿ‘‡๐Ÿป code sample for set up.

[Fact]
public void CreateLine_ReturnsTrue_WhenLineCreationSucceeds()
{
  // Arrange
  _mockSketchManager.Setup(sm => sm.CreateLine(It.IsAny<double>(), It.IsAny<double>(), It.IsAny<double>(), It.IsAny<double>(), It.IsAny<double>(), It.IsAny<double>()))
                    .Returns(_mockSketchSegment.Object);

  // Act
  bool result = _viewModel.CreateLine(null, 0, 0, 0, _mockSwApp.Object, _mockSketchManager.Object, 10, 10, 0);

  // Assert
  Assert.True(result);
  _mockSwApp.Verify(app => app.CloseAllDocuments(It.IsAny<bool>()), Times.Never);
  _mockSwApp.Verify(app => app.ExitApp(), Times.Never);
}

Please see below ๐Ÿ‘‡๐Ÿป image for reference.

4-add-test-2-to-test-class

Explanation of above CreateLine_ReturnsTrue_WhenLineCreationSucceeds is give below.

[Fact]
public void CreateLine_ReturnsTrue_WhenLineCreationSucceeds()
{

}
  • [Fact] :
    • This is a test attribute.
    • This attribute shows that this method is a test case that the xUnit test runner recognizes.
  • public :
    • This means that the CreateLine_ReturnsTrue_WhenLineCreationSucceeds method can be accessed from anywhere.
    • This is important, because xUnit test runner is external agent.
    • xUnit test runner need to have accessed to this CreateLine_ReturnsTrue_WhenLineCreationSucceeds method.
    • Because of this requirment we need to give public accessor.
  • void :
    • This is the return type of CreateLine_ReturnsTrue_WhenLineCreationSucceeds method.
    • Generally we donโ€™t return anything from test method.
    • Because of this we return void means we are not returning anything.
  • CreateLine_ReturnsTrue_WhenLineCreationSucceeds
    • This is the name of method.
    • This name is created in 3 different parts and combined with underscore โ€œ_โ€œ.
    • Different parts are explained below ๐Ÿ‘‡๐Ÿป:
      • Part 1: Name of method we are testing.
      • Part 2: Return value we are expecting.
      • Part 3: Condition for which we are testing the method.
// Arrange
_mockSketchManager.Setup(sm => sm.CreateLine(It.IsAny<double>(), It.IsAny<double>(), It.IsAny<double>(), It.IsAny<double>(), It.IsAny<double>(), It.IsAny<double>()))
                  .Returns(_mockSketchSegment.Object);
  • _mockSketchManager:
    • This is mocking object for SketchManager object.
  • _mockSketchManager.Setup():
    • We are using the Setup() method from _mockSketchManager object.
    • This is important and most basic one you should learn.
    • This Setup() method allow us to setup the behavior of object it is mocking and its members/methods.
      • Please follow me and you will be able to understand how we setup the child members/methods.
  • Setup(sm => sm.CreateLine(It.IsAny<double>(), It.IsAny<double>(), It.IsAny<double>(), It.IsAny<double>(), It.IsAny<double>(), It.IsAny<double>()))
    • sm is object we are mocking.
    • sm represent SketchManager.
    • From this sm object we will setup CreateLine method.
    • This method takes 6 double parameters.
    • We are defining that all 6 parameters will take any double value.
  • Returns(_mockSketchSegment.Object)
    • Here are setting up return value of CreateLine method.
    • Above we are saying, whenever CreateLine method called, return SketchSegment object from _mockSketchSegment.Object variable.
// Act
bool result = _viewModel.CreateLine(null, 0, 0, 0, _mockSwApp.Object, _mockSketchManager.Object, 10, 10, 0);

In above code, we are calling CreateLine method of _viewModel variable and store the return value into result variable.

  • _viewModel:
    • ViewModel variable whose method we want to test.
  • CreateLine:
    • Method we want to test.
  • CreateLine(null, 0, 0, 0, _mockSwApp.Object, _mockSketchManager.Object, 10, 10, 0)
    • Calling CreateLine method and passing parameters to method.
    • null: We are passing null value for SketchSegment parameter.
    • 0, 0, 0: X1, Y1, Z1 co-ordinate of start point.
    • _mockSwApp.Object: SldWorks object from _mockSwApp variable.
    • _mockSketchManager.Object: SketchManager object from _mockSketchManager variable.
    • 10, 10, 0: X2, Y2, Z2 co-ordinate of end point.
// Assert
Assert.True(result);
_mockSwApp.Verify(app => app.CloseAllDocuments(It.IsAny<bool>()), Times.Never);
_mockSwApp.Verify(app => app.ExitApp(), Times.Never);
  • Assert.True(result);:
    • We are checking value of result variable is True.
    • If return value is True then our asseertion is true.
  • _mockSwApp.Verify(app => app.CloseAllDocuments(true), Times.Never);:
    • Here we are verifying CloseAllDocuments() method Never called.
    • In our test method, we define that if we successully create SketchSegment object, then this CloseAllDocuments() will not be called.
  • _mockSwApp.Verify(app => app.ExitApp(), Times.Never);:
    • Here we are verifying ExitApp() method Never called.
    • In our test method, we define that if we successully create SketchSegment object, then this ExitApp() will not be called.

##

Before running test cases, we need to rebuild the Test project.

After rebuild, we see test cases in Test Explorer as shown in below ๐Ÿ‘‡๐Ÿป image.

5-test-cases-in-test-explorer

Now we run all test cases.

Please see below ๐Ÿ‘‡๐Ÿป image for reference.

final-result


This is it !!!

I hope my efforts will helpful to someone!

If you found anything to add or update, please let me know on my e-mail.

Hope this post helps you to Test Create Line Method.

If you like the post then please share it with your friends also.

Do let me know by you like this post or not!

Till then, Happy learning!!!

Updated: