Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
408 views
in Technique[技术] by (71.8m points)

c# - Testing BLE(Bluetooth Low Energy) in xamarin forms

How can I do unit testing for BLE(Bluetooth Low Energy) in xamarin forms. I am testing methods which implements the BLE Gatt operation using Nunit . I am able to do unit testing for the viewmodel. But how will I test the singleton classes where the BLE gatt operation is going on. This is the Data transfer class which acts as intermediate.

public class DataTransfer:IManager
{
  
    public ICharacteristic _characteristicsBLE;
    private static readonly object padlock = new object(); //Using Padloc to make code thread safe
    private static DataTransfer instance = null;
    public string _result;
    public IDevice _deviceBLE; //Contains information of BLE device
    private DataTransfer()
    {
    }

    //Instance of Singeleton class
    public static DataTransfer   Instance
    {
        get
        {
            if (instance == null)
            {
                lock (padlock)
                {
                    if (instance == null)
                    {
                        instance = new DataTransfer();
                    }
                }
            }
            return instance;
        }
    }
    public async Task connect(ScanData scanData, CancellationTokenSource token)
    {
        try
        {
            await BleManager.Instance.BleState(scanData, token);
           // await getCharacteristics(scanData, token);
        }
        catch(Exception ex)
        {
            await UserDialogs.Instance.AlertAsync("The data is incomplete scan again. Datatransfer");
        }
      
    }
    public async Task getCharacteristics(ScanData scanData, CancellationTokenSource token)
    {
        try
        {
            await BleManager.Instance.GetCharacteristics(scanData);
        }
        catch (Exception ex)
        {
            await UserDialogs.Instance.AlertAsync("The data is incomplete scan again. Datatransfer");
        }
    }     
}

This is the BLE manager class which has BLE gatt operations.

public class BleManager 
{
    
    private IBluetoothLE _bluetoothLe; 
    public IBluetoothService _bleState; //Reference for BluetoothService which has execution for turning ON bluetooth using Dependency service
    public IDevice _device; //Contains information of BLE device
    public IAdapter _adapter;
    public static readonly Guid SERVICE_ID =  Guid.Parse("00001805-0000-1000-8000-00805f9b34fb");  //Sevice ID of BLE GATT
    public static readonly Guid CHARACTERISTIC_ID_WRITE = Guid.Parse("00002B0F-0000-1000-8000-00805f9b34fb");  //Characteristic ID of BLE GATT Write
 
    public static readonly Guid CHARACTERISTIC_ID_READ = Guid.Parse("00002a2b-0000-1000-8000-00805f9b34fb");
 
    public string concat { get; set; }
    public string BLEresultnew { get; set; }
    public ICharacteristic _characteristicsBLE;
    public NativeDevice NativeDeviceAdd { get; private set; } //Class which contain name and address of BLE
    public string BleDeviceName { get; private set; }
    private const string SERVICE_NAME = "Current Time Service"; //Service Name of BLE GATT
    private static readonly object padlock = new object(); //Using Padloc to make code thread safe
    private static BleManager instance = null;

    private BleManager()
    {
    }

    //Instance of Singeleton class
    public static BleManager Instance
    {
        get
        {
            if (instance == null)
            {
                lock (padlock)
                {
                    if (instance == null)
                    {
                        instance = new BleManager();
                    }
                }
            }
            return instance;
        }
    }
   
   
    //Check if Bluetooth is ON or OFF. If Bluetooth is switched OFF in android then switch it ON.
    public async Task BleState(ScanData scanData, CancellationTokenSource token)
    {
            _bluetoothLe = CrossBluetoothLE.Current;
            if (_bluetoothLe.State == BluetoothState.Off)
            {
                if (Device.RuntimePlatform == Device.iOS)
                {
                await UserDialogs.Instance.AlertAsync("Switch On bluetooth");
                   
                }
                else
                {
                    _bleState = DependencyService.Get<IBluetoothService>();
                    _bleState.OpenBluetooth();
                    await ScanForDevices(scanData);
                }
            }
            else
            {
                await ScanForDevices(scanData);
            }
       
    }

    //Scan for BLE devices
    private async Task ScanForDevices(ScanData scanData, ConnectParameters connectParameters = default, CancellationToken token = default)
    {
        try
        {
            _device = null;
            _adapter = CrossBluetoothLE.Current.Adapter;
            _adapter.ScanMode = ScanMode.LowLatency;
            _adapter.ScanTimeout = 5000;
            Device.BeginInvokeOnMainThread(async () =>
            {
                _adapter.DeviceDiscovered += async (s, a) =>
            {
                NativeDeviceAdd = DependencyService.Get<INativeDevice>().ConvertToNative(a.Device);
                PropertyInfo propInfo = NativeDeviceAdd.GetType().GetProperty("Name");
                BleDeviceName = (string)propInfo.GetValue(NativeDeviceAdd, null);
         
            string substr = scanData.blename;
                if (BleDeviceName == substr)
                {

                    _device = a.Device;

                    await _adapter.StopScanningForDevicesAsync();
                    await ConnectForDevice(scanData);

                }

            };
            });
            await _adapter.StartScanningForDevicesAsync();
        }
        catch (DeviceConnectionException ex)
        {
          
            await UserDialogs.Instance.AlertAsync("Device got disconnected please scan again 1");
            return;

        }
        catch (Exception ex)
        {
            await UserDialogs.Instance.AlertAsync("Device got disconnected please scan again.The CancellationTokenSource has been disposed");
            return;
        }
    }


    //If the device is selected the connection is done here
    private async Task ConnectForDevice(ScanData scanData, ConnectParameters connectParameters = default, CancellationToken token = default)
    {
      
       
        try
        {
           
            _adapter.DeviceConnectionLost += async (s, a) =>
            {
                
                Device.BeginInvokeOnMainThread(async () =>
                {
                    Console.WriteLine("Device ConnectionLost : " + a.ErrorMessage);
                    await UserDialogs.Instance.AlertAsync("Device ConnectionLost :"+a.ErrorMessage);
                    var parameters2 = new ConnectParameters(forceBleTransport: true, autoConnect: true);
                    await _adapter.ConnectToDeviceAsync(_device, parameters2);
                    await GetCharacteristics(scanData);
                });

            };

            _adapter.DeviceDisconnected += async (s, a) =>
             {
                 Console.WriteLine("Device Disconnected : ");
                 await UserDialogs.Instance.AlertAsync("Device Disconnected :");
             };

            var parameters = new ConnectParameters(forceBleTransport: true,autoConnect:true);


            await _adapter.ConnectToDeviceAsync(_device, parameters);
            await GetCharacteristics(scanData);
        }
        catch (DeviceConnectionException ex)
        {
          
            Console.WriteLine("Exception while connecting and registering callbacks " + ex.Message);
            await UserDialogs.Instance.AlertAsync("Device got disconnected please scan again 2" + ex.Message);
         
        }
     

     }
    public async void disconnected()
    {
        await Application.Current.MainPage.Navigation.PopAsync();
        return;
        
    }

 
    public async Task GetCharacteristics(ScanData scanData, ConnectParameters connectParameters = default, CancellationToken token = default)
    {
        try
        {
        concat = null;
       
            var service = await _device.GetServiceAsync(SERVICE_ID);
            
       
            var characteristicRead = await service.GetCharacteristicAsync(CHARACTERISTIC_ID_READ);
            await ReadConfigData(characteristicRead);
      
            }
        catch (DeviceConnectionException ex)
        {

            await UserDialogs.Instance.AlertAsync("Device got disconnected please scan again 3");
         
        }
        catch (TaskCanceledException tce)
        {
            Console.WriteLine("Scan was cancelled");
        }
      

    }
    private async void OnDeviceDisconnected(object sender, DeviceEventArgs e) //Is OK to use async void here
    {
     
        await UserDialogs.Instance.AlertAsync("Device got disconnected  after scan");
     
    }
    private async void OnDeviceconnected(object sender, DeviceEventArgs e) //Is OK to use async void here
    {
        
            await UserDialogs.Instance.AlertAsync("Device got disconnected please scan again event");
    }
    public async  Task  WriteDataAsync(String data)
    {
        if (_characteristicsBLE != null)
        {
            try
            {

            
                byte[] senddata = Encoding.UTF8.GetBytes(data);
                int start = 0;
                while (start < senddata.Length)
                {
                    
                    int chunkLength = Math.Min(20, senddata.Length - start);
                    byte[] chunk = new byte[chunkLength];
                    Array.Copy(senddata, start, chunk, 0, chunkLength);
                    Device.BeginInvokeOnMainThread(async () =>
                   {
                   
                    await _characteristicsBLE.WriteAsync(chunk);
                    });
                    start += 20;
                    
                }

               
            }
            catch (Exception ex)
            {
                 
                Console.WriteLine(ex);
            }
        }


    }

    public async Task ReadConfigData(ICharacteristic characteristics)
    {
        if (characteristics != null)
        {
            try
            {
                await _adapter.ConnectToDeviceAsync(_device);
               
                    characteristics.ValueUpdated += (o, e) =>
                {
                      Device.BeginInvokeOnMainThread(async () =>
                     {
                 
                    var bytes = e.Characteristic.Value;
                 
                    BLEresultnew = System.Text.Encoding.UTF8.GetString(bytes);

                    Console.WriteLine(BLEresultnew);
                   
                    concat += BLEresultnew;
                  
                     });
                };
                
                    await characteristics.StartUpdatesAsync();
          
            }

            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
            
        }

    }
}

I have no clue how can I test these singeleton classes. Is there an


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...