6 Replies Latest reply on Nov 7, 2017 4:17 PM by ernstamort

    Are There Any Code Examples Available of Mocking Up the PI SDK for .NET Unit Tests?

    pmmcann

      I am curious if anyone has any, or is currently using means of mocking PI access for unit testing.

       

      My need stems from writing an application that I need to have relatively high code coverage. The application is using the PI SDK, and is a .NET Web API which allows iPads to remotely input data into our PI system and relational SQL databases. Some of the functionality can be relatively easily unit tested because it is SQL only entities that I have implemented as POCOs, which then have IQueryable repositories used to handle DAL logic, and then using dependency injection and Inversion of Control to pass things cleanly to the controller. This makes those controllers that respond to simple things like GET requests for a asset in the SQL database relatively painless, and testing the logic in those methods or the underlying data store relatively painless.

       

      My problem now stems from some of my fatter controllers that currently have PI SDK code executing business based logic along side transactions for my entity framework database context data access. Unit testing these has so far evaded me.

       

      One such method takes in an object with several CLR properties. These are then used to determine what actions should be taken, and if necessary, find a the correct Pi Unit, and create a PI Unit Batch as well as update records in several tables.

       

      How might I effectively unit test where I need to write data to the PI system without modifying the underlying PI Data?

       

      Actions like updating a tag and checking if the resulting performance equation activated properly with an expected result seem reasonable candidates for this kind of application test, do they not?

       

      I would appreciate any help anyone has on this. Also, unfortunately I am still limited to the PI-SDK, and cannot use the AF-SDK, Event Frames or PI Web API.

       

      Thanks!

        • Re: Are There Any Code Examples Available of Mocking Up the PI SDK for .NET Unit Tests?
          John Messinger

          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.

          2 of 2 people found this helpful
          • Re: Are There Any Code Examples Available of Mocking Up the PI SDK for .NET Unit Tests?
            pthivierge

            Hello Peter,

             

            I had an interesting discussion once with Roger Palmen and Rhys Kirk about unit testing, and Rhys gave me an explanation that I found useful on the idea of unit tests with our SDKs:

            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.

             

            David Hearn also once talked about using Microsoft Fakes in this post, Re: Unittest code using AF SDK .  This was for PI AF SDK, but maybe this can bring some relevant information.

            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

            1 of 1 people found this helpful
            • Re: Are There Any Code Examples Available of Mocking Up the PI SDK for .NET Unit Tests?
              John Messinger

              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?

              • Re: Are There Any Code Examples Available of Mocking Up the PI SDK for .NET Unit Tests?
                ernstamort

                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 ...

                1 of 1 people found this helpful