SOLIDWORKS C# API - Test Create Line Method
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.
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 ofSldWorks.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 theMainWindowViewModelTests
class. - No other part of the program can see or change it.
- This means that the
- 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.
- This indicates that once
- 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.
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 ofMainWindowViewModel
.
_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.
- TestCase 1 : When Line Creation Fails Returns False
- 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.
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 thisCreateLine_ReturnsFalse_WhenLineCreationFails
method.- Because of this requirment we need to give
public
accessor.
- This means that the
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.
- This is the return type of
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.
- This is the value we are assigning to
_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.
- This is mocking object for
_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.
- We are using the
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
representSketchManager
.- From this
sm
object we will setupCreateLine
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, returnnull
. - Since
CreateLine
method returnSketchSegment
type hence we need to cast this also while setting up return value.
- Here are setting up return value of
// 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.
- Calling
// 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 isfalse
. - If return value is
false
then our asseertion is true.
- We are checking value of
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.
- Similar to previous line, here we are checking value of
_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.
- Here we are verifying
_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.
- Here we are verifying
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.
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 thisCreateLine_ReturnsTrue_WhenLineCreationSucceeds
method.- Because of this requirment we need to give
public
accessor.
- This means that the
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.
- This is the return type of
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.
- This is mocking object for
_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.
- We are using the
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
representSketchManager
.- From this
sm
object we will setupCreateLine
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, returnSketchSegment
object from_mockSketchSegment.Object
variable.
- Here are setting up return value of
// 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 passingnull
value forSketchSegment
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.
- Calling
// 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 isTrue
. - If return value is
True
then our asseertion is true.
- We are checking value of
_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 thisCloseAllDocuments()
will not be called.
- Here we are verifying
_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 thisExitApp()
will not be called.
- Here we are verifying
##
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.
Now we run all test cases.
Please see below ๐๐ป image for reference.
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!!!