2 of 2 people found this helpful
So you specifically highlighted actions such as
updating a tag and checking if the resulting performance equation activated properly with an expected result
This shouldn't be too difficult to mock up with PI-SDK objects. I assume that by "updating a tag" you mean writing a new value or set of values to it. As you can independently create a PIValue object, you could initialise mock PIValues to hold your expected values and then run your assertions to determine if your code produces the expected result. This can be done without affecting underlying data, or even needing to connect to the server.
Testing if a "resulting performance equation activated properly with an expected result", I would assume that you are using something like the IPICalculation interface with a method such as Calculate. If this were the case, you would obviously still be needing to make a connection to the PI server in your unit test code, and then evaluating the returned PIValues against your expected values. You can't mock objects such as PIPoint that require a PIData object to test things such as data writes or data reads etc, without interacting with real PIPoints in a PIServer.
I've not unit tested PI-SDK code, only AFSDK, and found that you can't completely mock everything - for some things you still need to interact with an external system (the AF server, the Data Archive server etc), and the same would apply to PI-SDK code and objects.
The biggest issue I've found with unit testing data interactions using the AFSDK is the inability to isolate the tests sufficiently from the PI system such that you can have tests that will always produce the same results every time you run those tests (especially when reading data), regardless of how much time passes between those test runs. Unlike entity framework unit testing, you can't fully abstract the PI data layer.
1 of 1 people found this helpful
Reason you would need to perform these types of tests is that Unit Testing shouldn't utilize any external links/connections and should be self contained. What you would typically be testing is that your own code handles whatever you are retrieving from AF / PI. For example, you may want to test that your code encapsulates the creation of an Event Frame correctly but your code shouldn't be connecting to AF (thus SQL) and creating an Event Frame, you should instead create a Fake Event Frame and have your code handle the Fake Event Frame. The focus of this particular test is the encapsulating code not that AF (a dependency) is working correctly, but you still need to work with valid AF objects for the test to run correctly.
So for you this probably implies that you will need a layer in your code that will provide you PI SDK objects translated into objects that are specific to your application, this layer could be a dedicated class that wraps up all PI SDK related calls and returns data types that do not depend on the PI SDK. Then, in your unit tests, you can mock this layer, when defining mock objects you'll tell what is the data that the calls should return instead of having to perform a data call.
I was told by other OSIsoft developers from our Czech office that if you need to create tests object it may be best to consider usin Moq instead of Fakes as they are easier to maintain.
Hope this helps and let us know how it goes!
This topic does not raise so often, but its complexity would make it a good canditate for some GitHub samples I believe
The most recent project I've been involved in required a custom AFSDK application, which ended up being the most heavily unit tested AFSDK based code I've produced. I ended up using FakeItEasy as the mocking framework for my fake objects. I chose this in part over Moq partly because of what I saw in the documentation (too many "foos" and "bars" for me)
The thing I found with these mocking frameworks though, and they all seem to share this limitation, is that in the context of the AFSDK you can generally only create useful fake objects based on interfaces, and a limited number of other classes in the AFSDK. Admittedly my lack of significant experience with these frameworks in unit testing comes out here, but you are still constrained by the fact that many of the AFSDK objects are dependant upon the PISystem and/or AFDatabase objects, and as far as I can see, these can't be mocked or faked in any useful way.
I'm curious to hear what insight more experienced developers have had in this area. Care to comment Rick Davin?
Why do I feel like the school kid in back of the class that's staring out the window and suddenly the teacher calls out his name?
Sadly I have little experience with unit testing and mock data so I won't be able to contribute to the discussion (though I am eagerly following it). I was lucky in my previous job, in that for testing and development we had the hardware as well as sofware licensing to copy the production PI systems and test against a clone of real data. I was also lucky in that less than 5% of the applications we wrote used PISDK, and that was diminishing with each new release of AF.
Sorry Rick, you were the first person I thought of that might have been there and done that in this arena
1 of 1 people found this helpful
This is a common problem ...
I usually write an extension to the SDKs, so I get the method signature that I like. The PI objects are also too complex for my applications. For example the value object contains different value types and meta data whereas most of the apps I use can only understand simple types such as double, string, ....
So I flatten the structure and convert them to simpler structures. A digital state in a double type becomes then Double.NaN ...
If you write the extension, you can as well write the interface and then use dependency injection to make your code more reusable. That way its also easy to create a simulator class with the same interface methods for testing ....
Another way is to use NuGet Gallery | ImpromptuInterface 6.2.2
This is a similar approach for classes that done't have an Interface dll ...