Using Moq with NUnit in C# - c#

I am building a simple Airport program where planes can only take off / land if the weather is sunny and not stormy. This depends on the Weather class (which randomises the weather between sunny and stormy). However, for my tests, I want to mock the weather so I can test for all cases.
Here is my Weather.cs:
using System;
namespace ClassNameWeather
{
public class Weather
{
public Weather()
{
}
public string Forecast()
{
Random random = new Random();
var weather = random.Next(1, 11);
if (weather == 1 || weather == 2)
{
return "stormy";
}
else
{
return "sunny";
}
}
}
}
Here is my Airport.cs:
using System;
using System.Collections.Generic;
using ClassNamePlane;
using ClassNameWeather;
namespace ClassNameAirport
{
public class Airport
{
private string _AirportName { get; set; }
public List<Plane> planes;
private Weather _weather = new Weather();
public Airport(string _airportName, Weather weather)
{
planes = new List<Plane>();
_AirportName = _airportName;
}
public void Land(Plane plane)
{
if (_weather.Forecast() != "stormy")
{
planes.Add(plane);
Console.WriteLine($"{ plane.Name } has landed at {_AirportName}");
}
else
{
throw new Exception("It's too stormy to land");
}
}
public void TakeOff(Plane plane)
{
if (_weather.Forecast() != "stormy")
{
planes.Remove(plane);
Console.WriteLine($"{ plane.Name } has departed from {_AirportName}");
}
else
{
throw new Exception("It's too stormy to take off");
}
}
public int GetPlaneCount()
{
Console.WriteLine($"Number of planes at {_AirportName}: {planes.Count}");
return planes.Count;
}
public void GetPlaneNames()
{
planes.ForEach(plane => Console.WriteLine((plane as Plane).Name));
}
public List<Plane> GetPlaneList()
{
return planes;
}
}
}
And here is the test that I'm trying to use the mock in:
using NUnit.Framework;
using ClassNameAirport;
using ClassNamePlane;
using ClassNameWeather;
using Moq;
namespace AirportTest
{
public class AirportTest
{
Airport airport = new Airport("TestAirport", weather);
Plane plane = new Plane("TestPlane");
[Test]
public void PlaneCanLand()
{
var weather = new Mock<Weather>();
weather.Setup(x => x.Forecast()).Returns("sunny");
airport.Land(plane);
Assert.IsTrue(airport.planes.Contains(plane));
}
public void PlaneCanTakeOff()
{
airport.Land(plane);
airport.TakeOff(plane);
Assert.IsFalse(airport.planes.Contains(plane));
}
}
}
This line: Airport airport = new Airport("TestAirport", weather); is not working, saying the name weather does not exist.
Can anyone help me to make sure I am using Moq correctly? I'm new to C# and any advice is much appreciated.
Thank you!
UPDATE
I have fixed this, but now receive the following error:
System.NotSupportedException : Unsupported expression: x => x.Forecast()
Non-overridable members (here: Weather.Forecast) may not be used in setup / verification expressions.
Does anyone know how to fix this please?

You can introduce interface IWeather like
public interface IWeather
{
string Forecast();
}
Than implement it in Weather class. Pass IWeather reference to AirPort class and setup a mock for that.
var weather = new Mock<IWeather>();
weather.Setup(x => x.Forecast()).Returns("sunny");
...
var airport = new Airport("TestAirport", weather.Object)
And do not initialize it in Airport class directly private Weather _weather = new Weather(); (your constructor argument is not used), do like this
public class Airport
{
private string _AirportName { get; set; }
public List<Plane> planes;
private readonly IWeather _weather;
public Airport(string _airportName, IWeather weather)
{
planes = new List<Plane>();
_weather = weather;
}
...
}

You have not declared the variable weather. I suggest that you create an Initialize method and attribute it with TestInitialze
[TestInitialize]
public void TestInitialize()
{
var weather = new Mock<Weather>();
var airport = new Airport("TestAirport", weather)
}

Related

Unity Container resolve calling same parameterized constructor twice

I'm using a unity container and I'm trying to resolve by passing the object to the parameterized constructor, I noticed the same constructor is called twice, the first time it takes appropriate values, and not sure why it is calling again and it overrides with a blank object, can someone help me what is happening over here, not able to solve it.
//////////////////////////////////////////////////////////////////////
if (container == null)
{
container = new UnityContainer().AddExtension(new Diagnostic());
container.RegisterType<ISubscribeService,OOrderProc.Common.SubscribeService.SubscribeService>();
container.RegisterType<IBaseOrderProcessing, BaseSubscribe>("Subscribe");
}
SubscribeDetails m = new SubscribeDetails();
m.SubscribeType = SubscribeType.ACTIVATE;
m.SubscribeName = "TEST";
var b = container.Resolve<IBaseOrderProcessing>("Subscribe",new DependencyOverride<BaseSubscribe>(new OOrderProc.Common.SubscribeService.SubscribeService(m)));
//////////////////////////////////////////////////////////////////////
public interface IBaseOrderProcessing
{
void ProcessOrder();
}
public interface ISubscribeService
{
SubscribeType SubscribeType { get; set; }
void ActivateSubscribe();
void UpgradeSubscribe();
}
// Strategy Pattern 1 => Subscribe is one of the "if" condition
public class BaseSubscribe : IBaseOrderProcessing
{
private ISubscribeService _SubscribeService = null;
public BaseSubscribe(ISubscribeService SubscribeService)
{
_SubscribeService = SubscribeService;
}
public void ProcessOrder()
{
if (_SubscribeService.SubscribeType == SubscribeType.ACTIVATE)
_SubscribeService.ActivateSubscription();
if (_SubscribeService.SubscribeType == SubscribeType.UPGRADE)
_SubscribeService.UpgradeSubscription();
}
}
// Writing another class to simplify is correct ?????
public class SubscribeService : ISubscribeService
{
private SubscribeDetails _Subscribedetails = null;
public SubscribeType SubscribeType { get; set; }
public SubscribeService(SubscribeDetails Subscribedetails)
{
_Subscribedetails = Subscribedetails;
SubscribeType = Subscribedetails.SubscribeType;
}
public void ActivateSubscription()
{
// Code to save the Subscribe details in the database
Console.WriteLine($"\n\nSubscribe {_Subscribedetails.SubscribeId} for {_Subscribedetails.SubscribeName} activated for order Id: {_Subscribedetails.OrderId}" +
$" from {_Subscribedetails.SubscribeStartDate} to {_Subscribedetails.SubscribeEndDate}");
}
public void UpgradeSubscription()
{
// Code to upgrade the Subscribe details in the database
Console.WriteLine($"\n\nSubscribe {_Subscribedetails.SubscribeId} for {_Subscribedetails.SubscribeName} upgraded for order Id: {_Subscribedetails.OrderId}" +
$" from {_Subscribedetails.SubscribeStartDate} to {_Subscribedetails.SubscribeEndDate}");
}
}
I resolved using below code:
container.RegisterType<IBaseOrderProcessing, BaseSubscribe>("Subscribe", new InjectionConstructor(new OOrderProc.Common.SubscribeService.SubscribeService((SubscribeDetails)obj)));
return container.Resolve<IBaseOrderProcessing>("Subscribe");

You must add a reference to assembly 'UnityEngine.AndroidJNIModule

I am very new at Unity and I tried to integrate Huawei Mobile Service plugin and I got this error.
The type 'AndroidJavaObject' is defined in an assembly that is not referenced. You must add a reference to assembly 'UnityEngine.AndroidJNIModule
Is there anyone who encounter this problem before?
Thank you.
Edit
This code is belong to plugin.
using HuaweiMobileServices.Id;
using HuaweiMobileServices.Utils;
using System;
using UnityEngine;
namespace HmsPlugin
{
public class AccountManager : MonoBehaviour
{
public static AccountManager GetInstance(string name = "AccountManager") => GameObject.Find(name).GetComponent<AccountManager>();
private static HuaweiIdAuthService DefaultAuthService
{
get
{
Debug.Log("[HMS]: GET AUTH");
var authParams = new HuaweiIdAuthParamsHelper(HuaweiIdAuthParams.DEFAULT_AUTH_REQUEST_PARAM).SetIdToken().CreateParams();
Debug.Log("[HMS]: AUTHPARAMS AUTHSERVICE" + authParams);
var result = HuaweiIdAuthManager.GetService(authParams);
Debug.Log("[HMS]: RESULT AUTHSERVICE"+ result);
return result;
}
}
public AuthHuaweiId HuaweiId { get; private set; }
public Action<AuthHuaweiId> OnSignInSuccess { get; set; }
public Action<HMSException> OnSignInFailed { get; set; }
private HuaweiIdAuthService authService;
// Start is called before the first frame update
void Awake()
{
Debug.Log("[HMS]: AWAKE AUTHSERVICE");
authService = DefaultAuthService;
}
public void SignIn()
{
Debug.Log("[HMS]: Sign in " + authService);
authService.StartSignIn((authId) =>
{
HuaweiId = authId;
OnSignInSuccess?.Invoke(authId);
}, (error) =>
{
HuaweiId = null;
OnSignInFailed?.Invoke(error);
});
}
public void SignOut()
{
authService.SignOut();
HuaweiId = null;
}
}
}
Picture of the problem is here.
The problem is about my unity. I had no AndroidJNI module so I got this error. Finally I uninstall current version then install new version of Unity and problem is solved. In the new version AndroidJNI module is came automatically.

Proper Way to Test a file method with .net

I'm new to .net and testing. My following code looks like this:
using System.Xml.Linq;
public class AnimalXmlService
{
public Animal GetAnimalInfoFromXml(string url) {
XElement xml_doc = GetXmlInfo(url);
if (xml_doc == null)
{
return null;
} else {
XElement animal_info = xml_doc.Element("Animal");
string animal_name = GetAnimalName(animal_info);
int animal_id = GetAnimalId(animal_info);
return new Animal(animal_id, animal_name);
}
}
private XElement GetXmlInfo(string url)
{
try
{
XElement animal_xml_info = XElement.Load(url);
return animal_xml_info;
}
catch
{
return null;
}
}
private int GetAnimalName(XElement animal_info)
{
....
}
}
My question is how do I stub the GetAnimalInfoFromXml to return a file? I have the sample xml file that I will be using instead of making a request. Here's my following test. I'm also wondering if there are better ways to refactor this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NUnit.Framework;
namespace AnimalXmlService
{
[TestFixture]
public class AnimalXmlTest
{
[Test]
public void extracts_valid_name()
{
//get xml file?
animalService AnimalXmlService = new AnimalXmlService();
name = animalService.GetAnimalName(xml_file);
Assert.AreEqual(name, "bobby the tiger");
}
[Test]
public void extracts_valid_id()
{
//get xml file?
xml_file = fetch_file //is this appropriate?
animalService AnimalXmlService = new AnimalXmlService();
id = animalService.GetAnimalId(xml_file);
Assert.AreEqual(name, "2");
}
}
}
In this situations you can use test doubles.
First , you should make your codes more testable ( Breaking dependency )
public class AnimalXmlService
{
private readonly IXmlReader _xmlReader;
public AnimalXmlService(IXmlReader xmlReader)
{
this._xmlReader = xmlReader;
}
public Animal GetAnimalInfoFromXml(string url)
{
XElement xml_doc = _xmlReader.Load(url);
if (xml_doc == null)
{
return null;
}
else
{
XElement animal_info = xml_doc.Element("Animal");
string animal_name = GetAnimalName(animal_info);
int animal_id = GetAnimalId(animal_info);
return new Animal(animal_id, animal_name);
}
}
}
And then you should create a stub to replace your real dependency. ( Also you can use frameworks like NSubstitute,Mock,...)
public class XmlReaderStub : IXmlReader
{
public XElement XElement { get; set; }
public XElement Load(string url)
{
return XElement;
}
}
And finally
public class AnimalXmlTest
{
[Test]
public void extracts_valid_name()
{
var stub = new XmlReaderStub();
stub.XElement = new XElement(); // some XElement
animalService AnimalXmlService = new AnimalXmlService(stub);
name = animalService.GetAnimalName();
Assert.AreEqual(name, "bobby the tiger");
}
}
You can have another method in your class like the one below which returns an XmlDocument.
public XmlDocument GetXmlFile()
{
XmlDocument doc = new XmlDocument();
doc.LoadXml("<Animal><Name>Bobby the tiger</Name></Animal>");
return doc;
}

C# method Linq variable return

hope your help :)
I search to make the result of the LinQ Variable bellow "ES" available in an other method.
public void Contract_ES(QCAlgorithm Algorithm_ES, Slice slice)
{
foreach(var chain in slice.FutureChains)
{
var ES = (from futuresContract in chain.Value.OrderBy(x => x.Expiry)
where futuresContract.Expiry > Algorithm_ES.Time.Date.AddDays(1)
select futuresContract).FirstOrDefault();
}
}
I downloaded QuantConnect just to get an idea what you're trying to do. The example below should at least not yield any errors, but I haven't tried the output.
using QuantConnect.Data;
using System.Linq;
using QuantConnect.Data.Market;
namespace QuantConnect.Algorithm
{
public interface IFuturesContractSelector_ES
{
FuturesContract GetFuturesContract_ES(QCAlgorithm Algorithm_ES, Slice slice);
}
public class Contract_ES : IFuturesContractSelector_ES
{
private readonly Slice _Slice;
private readonly QCAlgorithm _Algorithm_ES;
public Contract_ES(QCAlgorithm Algorithm_ES)
{
_Algorithm_ES = Algorithm_ES;
}
public Contract_ES(Slice slice)
{
_Slice = slice;
}
public FuturesContract GetFuturesContract_ES(QCAlgorithm Algorithm_ES, Slice slice)
{
foreach (var chain in slice.FutureChains)
{
if (chain.Value.Symbol.Value.StartsWith("ES"))
{
return (from futuresContract in chain.Value.OrderBy(x => x.Expiry)
where futuresContract.Expiry > Algorithm_ES.Time.Date.AddDays(1)
select futuresContract).FirstOrDefault();
}
}
return null;
}
}
}
Or you could do an extension on the Slice class:
using QuantConnect.Data;
using System.Linq;
using QuantConnect.Data.Market;
namespace QuantConnect.Algorithm
{
public static class SliceExtensions
{
public static FuturesContract GetFuturesContract_ES(this Slice slice, QCAlgorithm Algorithm_ES)
{
foreach (var chain in slice.FutureChains)
{
if (chain.Value.Symbol.Value.StartsWith("ES"))
{
return (from futuresContract in chain.Value.OrderBy(x => x.Expiry)
where futuresContract.Expiry > Algorithm_ES.Time.Date.AddDays(1)
select futuresContract).FirstOrDefault();
}
}
return null;
}
}
public class Test
{
public void TestMyMethod(Slice slice)
{
var contract = slice.GetFuturesContract_ES(new QCAlgorithm());
//... do something
}
}
}
I tried to create an interface then the method, result is :
using QuantConnect.Securities;
namespace Quant
{
public interface IFuturesContractSelector_ES
{
void GetFuturesContract_ES(QCAlgorithm Algorithm_ES, Slice slice);
}
}
public class Contract_ES : IFuturesContractSelector_ES
{
private readonly Slice _Slice;
private readonly QCAlgorithm _Algorithm_ES;
public Contract_ES(QCAlgorithm Algorithm_ES)
{
_Algorithm_ES = Algorithm_ES;
}
public Contract_ES(Slice slice)
{
_Slice = slice;
}
public void GetFuturesContract_ES(QCAlgorithm Algorithm_ES, Slice slice)
{
foreach(var chain in slice.FutureChains)
{
if (chain.Value.Symbol.StartsWith("ES"))
{
var ES = (from futuresContract in chain.Value.OrderBy(x => x.Expiry)
where futuresContract.Expiry > Algorithm_ES.Time.Date.AddDays(1)
select futuresContract).FirstOrDefault();
}
}
return ES;
}
}
At the Line return ES, I get this error :
The name "ES" does not exist in the current context.
Weird because I have another method build in this way, with no prob -_-
Maybe using foreach statement that cause the non possible return of "var ES" ?

How to change value in one class if value changes in another

Let's say I have a parameter in my ViewModel:
public string ChosenQualityParameter
{
get => DefectModel.SelectedQualDefectParameters?.Name ?? "Не выбран параметр";
}
and I have a class DefectModel with parameter SelectedQualDefectParameters.Name in it. I want to change the UI binded to ChosenQualityParameter, when theName parameter changes too.
But I don't know how to do this properly. Any suggestions? Thanks in advance.
You might define your ViewModel class like this:
public class ViewModel
{
private DefectModel _defectModel;
public ViewModel(DefectModel defectModel)
{
_defectModel = defectModel;
}
public string ChosenQualityParameter
{
get => _defectModel.SelectedQualDefectParameters?.Name ?? "Не выбран параметр";
}
}
I personally do not like such dependencies in viewmodels, but it might get the job done here. It seems to work in a console application anyway:
using System;
public class Parameters
{
public string Name { get; set; }
}
public class DefectModel
{
public Parameters SelectedQualDefectParameters { get; set; }
}
public class ViewModel
{
private DefectModel _defectModel;
public ViewModel(DefectModel defectModel)
{
_defectModel = defectModel;
}
public string ChosenQualityParameter
{
get => _defectModel.SelectedQualDefectParameters?.Name ?? "Не выбран параметр";
}
}
class Program
{
static void Main()
{
var defectModel = new DefectModel
{
SelectedQualDefectParameters = new Parameters
{
Name = "test"
}
};
var viewModel = new ViewModel(defectModel);
Console.WriteLine(viewModel.ChosenQualityParameter);
defectModel.SelectedQualDefectParameters.Name = "changed";
Console.WriteLine(viewModel.ChosenQualityParameter);
Console.ReadKey();
}
}
Thanks to #Knoop and #BartHofland, I've solved my issue by using INotifyPropertyChanged in my DefectModel and SelectedQualDefectParameters classes.
For setting ChosenQualityParameter I used MessagingCenter to send new value.

Categories

Resources