Test framework for .Net Micro

In my constant effort to address my many weaknesses as a programmer, I’ve been trying to develop a more systematic approach to testing. I kind of like some of the unit testing frameworks I’ve seen for .Net desktop but have never seen one for .Net Micro until now. Has anyone every used https://visualstudiogallery.msdn.microsoft.com/dc3cc533-daf7-4cce-815e-7399125696f5 and can report on their experience? Any other comments, suggestions or ideas about more systematic testing approaches?

Thanks - Gene

3 Likes

@ Gene - Have not seen that before. Interesting.

Not to be arrogant, but I have realized that the maturity of software development for embedded devices, due to resource constraints, and “is this possible” focus, are not very high.

This type of contributions are a good sign that we are maturing. :whistle:

May I just also put a word forward for the STAMA framework for NETMF which I am a strong supporter for. See more [url]Rik Mayall and the Bastard Squad performing My Generation, 1983 - YouTube

Unit testing is somewhat complicated in NETMF projects because you can’t really run the program until it’s on the chip, and while many generic functions may work in emulator, there are also GHI libraries that [em]only [/em]work inside the chip.

@ njbuch - I use StaMa, too. It has a very awkward non-.NET style API, but, I have to admit, once you get through, it works quite well…

Here is a new version of MFUnitTest that supports Visual Studio 2015 + Micro Framework 4.4 (good bye slow debugging):

I write a lot of reusable code which runs on RTU Controllers (EMX, G120) and PC, and for me it’s best solution…
Waiting for LILLUM and UWP…

2 Likes

@ Gene, Real unit testing would have an emulator running the netmf device + data that will mimic the functions of µC in the real envrionment. What you can do instead is to test your functions! C# has the [em]partial[/em] class declaration. Visual studio allow allows you to link existing c# files from one project into another. What this means is that you can write a class for NETMF but still create unit tests that verify your code.

E.g. Let’s say we wanted to call SPI.WriteRead. Well there is no Microsoft.SPOT.Hardware.SPI.WriteRead in Big DOT Net Framework, you can stub one out in a unit test. then based on what you call the method with; your test will respond accordingly. Then when you compile the MF code for the device, you can expect the same result that you did in the test.


 #region Assembly Microsoft.SPOT.Hardware.dll, v4.3.1.0
// C:\Program Files (x86)\Microsoft .NET Micro Framework\v4.3\Assemblies\le\Microsoft.SPOT.Hardware.dll
 #endregion

using System;

namespace Microsoft.SPOT.Hardware {
    public sealed class SPI : IDisposable {
        public SPI(SPI.Configuration config);

        public SPI.Configuration Config { get; set; }

        public void Dispose();
        public void Write(byte[] writeBuffer);
        public void Write(ushort[] writeBuffer);
        public void WriteRead(byte[] writeBuffer, byte[] readBuffer); //implement method and do test logic
        public void WriteRead(ushort[] writeBuffer, ushort[] readBuffer);
        public void WriteRead(byte[] writeBuffer, byte[] readBuffer, int startReadOffset);
        public void WriteRead(ushort[] writeBuffer, ushort[] readBuffer, int startReadOffset);
        public void WriteRead(byte[] writeBuffer, int writeOffset, int writeCount, byte[] readBuffer, int readOffset, int readCount, int startReadOffset);
        public void WriteRead(ushort[] writeBuffer, int writeOffset, int writeCount, ushort[] readBuffer, int readOffset, int readCount, int startReadOffset);

        public enum SPI_module {
            SPI1 = 0,
            SPI2 = 1,
            SPI3 = 2,
            SPI4 = 3,
        }

        public class Configuration {
            public readonly Cpu.Pin BusyPin;
            public readonly bool BusyPin_ActiveState;
            public readonly bool ChipSelect_ActiveState;
            public readonly uint ChipSelect_HoldTime;
            public readonly Cpu.Pin ChipSelect_Port;
            public readonly uint ChipSelect_SetupTime;
            public readonly bool Clock_Edge;
            public readonly bool Clock_IdleState;
            public readonly uint Clock_RateKHz;
            public readonly SPI.SPI_module SPI_mod;

            public Configuration(Cpu.Pin ChipSelect_Port, bool ChipSelect_ActiveState, uint ChipSelect_SetupTime, uint ChipSelect_HoldTime, bool Clock_IdleState, bool Clock_Edge, uint Clock_RateKHz, SPI.SPI_module SPI_mod);
            public Configuration(Cpu.Pin ChipSelect_Port, bool ChipSelect_ActiveState, uint ChipSelect_SetupTime, uint ChipSelect_HoldTime, bool Clock_IdleState, bool Clock_Edge, uint Clock_RateKHz, SPI.SPI_module SPI_mod, Cpu.Pin BusyPin, bool BusyPin_ActiveState);
        }
    }
}

Method under UNIT test


public static void Initilize() {
        dSpinConfig = new SPI.Configuration((Cpu.Pin)FEZCerbuino.Pin.Gadgeteer.Socket1.Pin4,
            false, // Chip Select, active-low
            0, // millisecond setup time
            0, // millisecond hold time
            true, // Clock low on idle
            true, // Data valid on rising edge
            5000, // 5000Khz
            SPI.SPI_module.SPI1);
        spiPort = new SPI(dSpinConfig);
        while (true) {
        
            byte[] _out = new byte[] { (byte)DateTime.Now.Millisecond, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
            byte[] _in = new byte[_out.Length];
            spiPort.WriteRead(_out, _in);
            bool _isGood = false;
            for (int i = 0; i < _in.Length; i++) {
                if (_out[0] == _in[i]) {
                    _isGood = true;
                    break;
                }
            }

            if (_isGood) {
                Debug.Print("dSPIN SPI Communication is good.");
                break; //TODO: Remove break if testing needed
            }
            else {
                Debug.Print("ERROR: Value not found in input array.");
            }
            
            Thread.Sleep(1000);
        }
        
    }

@ Gene -

My approach for unit tests in .NET Microframework is to create “full .NET” additional class library for each microframework project within solution by adding code files as links so I can use all benefits that comes with regular .NET framework (mocking libraries and test runners).

In my case I have one unit tests project per each project within solution (linked to additional full .Net lib). This combined with Moq (mocking library) works great for me. I use a lot of abstractions (e.g. interfaces, wrappers, factory patters) for classes that are microframework specific (e.g. Microsoft.SPOT namespace) in order to compile them in “full” framework. For those microframework specific parts of code I just wrote simple Fakes/Stubs - there are only few of them.

What I miss with the MFUnitTest is that it doesn’t have mocking library (I am not sure if it is even possible to write one in microframework) also task runner is not as slick as one built in visual studio.

I think unit tests are very useful even in embedded solutions especially having such great environment like .NET and VS and the goal is to check your logic not ensuring code runs on a real device. Actually I wonder how to do proper integration tests but this is something for another post :wink:

Thanks for all the info. I’m obviously going to have to do some reading and then try some of the techniques you all have suggested.

@ Gene -

I recommend reading this book, great stuff about unit testing - Roy Osherove, The Art of Unit Testing.

Wouldn’t that be integration testing?

@ bigfont - Nah, integration testing would be having the netmf device placed with the system that it is intending to work in. So if it’s a robot, then testing the device while its in the system would be integration testing.