Using Moq the Start() method keeps retuning a null object - c#

I'm having trouble figuring out why I can't test my driver variable, it keeps coming back null with I call Start(). I basically would like to access that variable and test it.
My current test that isn't working:
[TestMethod]
public void Start_Default_IsChrome2()
{
var dummyManager = new Mock<IRemoteDriver>();
var mockDriver = new Mock<IWebDriver>();
dummyManager.Setup(x => x.CreateRemoteWebDriver(new ChromeOptions()))
.Returns(It.IsAny<RemoteWebDriver>());
var session = new SauceSession(dummyManager.Object);
//The Start() keeps returning a null object
var driver = session.Start();
var capabilities = driver.Capabilities;
capabilities.GetCapability("browserName").Should().Be("chrome");
}
Dependency to be mocked
public interface IRemoteDriver
{
IWebDriver CreateRemoteWebDriver(ChromeOptions chromeOptions);
}
Subject Under Test
public SauceSession(IRemoteDriver driverManager)
{
remoteDriverManager = driverManager;
}
public RemoteWebDriver Start()
{
sauceUserName = Environment.GetEnvironmentVariable("SAUCE_USERNAME", EnvironmentVariableTarget.User);
sauceAccessKey = Environment.GetEnvironmentVariable("SAUCE_ACCESS_KEY", EnvironmentVariableTarget.User);
sauceOptions = new Dictionary<string, object>
{
["username"] = sauceUserName,
["accessKey"] = sauceAccessKey
};
var chromeOptions = new ChromeOptions
{
BrowserVersion = "latest",
PlatformName = "Windows 10",
UseSpecCompliantProtocol = true
};
chromeOptions.AddAdditionalCapability("sauce:options", sauceOptions, true);
//This keeps returning a null
return (RemoteWebDriver)remoteDriverManager.CreateRemoteWebDriver(chromeOptions);
}
If it helps, the Concrete implementation works just fine and that test looks like this:
[TestMethod]
public void Start_Default_IsChrome()
{
var session = new SauceSession();
var driver = session.Start();
var capabilities = ((RemoteWebDriver)driver).Capabilities;
capabilities.GetCapability("browserName").Should().Be("chrome");
}
Everything else is the same except the object that I set here:
public SauceSession()
{
remoteDriverManager = new ConcreteRemoteWebDriver();
}
class ConcreteRemoteWebDriver : IRemoteDriver
{
public IWebDriver CreateRemoteWebDriver(ChromeOptions chromeOptions)
{
return new RemoteWebDriver(new Uri("https://ondemand.saucelabs.com/wd/hub"),
chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600));
}
}
Here's the RemoteWebDriver:
public class RemoteWebDriver : IWebDriver, ISearchContext, IDisposable, IJavaScriptExecutor, IFindsById, IFindsByClassName, IFindsByLinkText, IFindsByName, IFindsByTagName, IFindsByXPath, IFindsByPartialLinkText, IFindsByCssSelector, ITakesScreenshot, IHasInputDevices, IHasCapabilities, IHasWebStorage, IHasLocationContext, IHasApplicationCache, IAllowsFileDetection, IHasSessionId, IActionExecutor

You've done your setup improperly.
dummyManager.Setup(x => x.CreateRemoteWebDriver(new ChromeOptions()))
.Returns(It.IsAny<RemoteWebDriver>());
Two things here:
You're matching on precisely an instance of new ChromeOptions(). When determining which object to return, Moq will check if the arguments passed to CreateRemoteWebDriver are the same as the ones provided in the setup. It's unlikely that
new ChromeOptions
{
BrowserVersion = "latest",
PlatformName = "Windows 10",
UseSpecCompliantProtocol = true
};
and
new ChromeOptions()
will evaluate as equal, meaning that this setup won't be matched.
You probably just meant to use It.IsAny<ChromeOptions>(), like this
dummyManager.Setup(x => x.CreateRemoteWebDriver(It.IsAny<ChromeOptions>()))
The second issue is that your return value is explicitly null.
It.IsAny<T>() always returns the default value for T. The It methods are all only used for argument matching within the Setup expression. If you use them outside of a setup expression, you're just going to get the default value of the generic argument, which in this case is a null value. It's a shame that the Moq library doesn't make this improper usage a loud error message. Consequently, you'll need to provide an actual instance of RemoteWebDriver as a return value. (Or if you can decouple the implementation from a particular concrete type, you could just return something that implements IWebDriver.)
That value could be another Mock object, potentially, but it needs to be something you've either created ahead of time, or something that can be created via the Returns callback.
A correct setup might look something like:
var mockDriver = new Mock<RemoteWebDriver>();
dummyManager.Setup(x => x.CreateRemoteWebDriver(It.IsAny<ChromeOptions>()))
.Returns(mockDriver.Object); //This could throw an exception if RemoteWebDriver needs arguments.
A small caveat is that you will actually create a RemoteWebDriver instance as a result. If that has undesirable side effects (such as creating a chrome window), you will want to consider changing your strategy from using a particular concrete type to some interface or abstract class. If you did that, the setup might look something like the below:
var mockDriver = new Mock<IWebDriver>();
dummyManager.Setup(x => x.CreateRemoteWebDriver(It.IsAny<ChromeOptions>()))
.Returns(mockDriver.Object);

Related

System.Diagnostics.ActivitySource.StartActivity returns null

I haven't find the way to make activitySource.StartActivity return non-null activity, which is different comparing to DiagnosticSource.StartActivity behavior. Is it expected? Am I'missing something obvious?
I can see docs says: "The created activity object, if it had active listeners, or null if it has no event listeners." The following test still fails, what's the correct way of initializing ActivityListener? The package I'm using is "System.Diagnostics.DiagnosticSource" Version="5.0.0".
[TestMethod]
public void Start_Not_Null_When_ActivityListener_Added_And_ShouldListenTo_Explicitly_Defined_Activity()
{
var activitySource = new ActivitySource("ActivitySourceName");
var activityListener = new ActivityListener
{
ShouldListenTo = s => true
};
ActivitySource.AddActivityListener(activityListener);
using var activity = activitySource.StartActivity($"MethodType:/Path");
Assert.IsNotNull(activity);
}
This test pass with the help from github:
[TestMethod]
public void Start_Not_Null_When_ActivityListener_Added_And_ShouldListenTo_Explicitly_Defined_Activity()
{
var activitySource = new ActivitySource("ActivitySourceName");
var activityListener = new ActivityListener
{
ShouldListenTo = s => true,
SampleUsingParentId = (ref ActivityCreationOptions<string> activityOptions) => ActivitySamplingResult.AllData,
Sample = (ref ActivityCreationOptions<ActivityContext> activityOptions) => ActivitySamplingResult.AllData
};
ActivitySource.AddActivityListener(activityListener);
using var activity = activitySource.StartActivity("MethodType:/Path");
Assert.IsNotNull(activity);
}
The answer to this is you need to include a ActivitySamplingResult that's not set to None. The default appears to be none. MaGu's answer works because they set:
Sample = (ref ActivityCreationOptions activityOptions) => ActivitySamplingResult.AllData
The documentation for the method around StartActivity says it needs a listener but this is not the complete story you need an active listener that will do something with the activity. Setting the sample to None means it's effectively not in

Method not entered in test case, works when ran normally

I have a very weird issue and I am clueless as to what is causing this behaviour.
I will provide the relevant code of two classes, to keep this short.
Class A has a method that gets an xml document and puts that in an XDocument object, it uses a method from class B for this. Then it uses a different but similar method from class B to add some additional xml to the XDocument.
For some reason, when I run the test cases, the second method from Class B is never entered. Instead, it gives back null.
Here is the code:
First call to a method in class B, from class A
// Get view (xml) for current supplier
XDocument navigationView = ProductBUS.GetProductNavigationXDocument(suppID, viewName, selectedProductNavigationView);
Second call to a method in class B, from class A (this is the faulty one)
if (true)
{
navigationView = ProductBUS.AddOptionsToNavigationMenu(navigationView);
}
(The if(true) is placeholder code, will be changed in the future to a boolean value. This value needs to come from the DB, which is empty at this point.)
The methods in class B, 1 and 2 respectively.
public XDocument GetProductNavigationXDocument(Guid supplierID, String viewName, string selectedProductNavigationView)
{
// TODO : implementing full scale DI
INavigationViewFactory factory = new NavigationViewFactory();
INavigationView navigationXml = factory.Create(NavigationViewTypes.Product);
return navigationXml.GetNavigationXDocument(supplierID, viewName, selectedProductNavigationView);
}
And the second one (which is never entered)
public XDocument AddOptionsToNavigationMenu(XDocument menu)
{
menu.Element(XmlNames.NodeNames.MenuItems).Add(
new XElement(XmlNames.NodeNames.MenuItem,
new XAttribute(XmlNames.AttributeNames.ID, "27301D05-EBBB-4F39-AC74-B0E944F26C52"),
new XAttribute(XmlNames.AttributeNames.DefaultName, "Options"),
new XAttribute(XmlNames.AttributeNames.NameTranslationID, "9999"),
new XAttribute(XmlNames.AttributeNames.DisplayMode, "Options"),
new XElement(XmlNames.NodeNames.MenuItem,
new XAttribute(XmlNames.AttributeNames.ID, "27301D05-EBBB-4F39-AC74-B0E944F26C57"),
new XAttribute(XmlNames.AttributeNames.NameTranslationID, "9999"),
new XAttribute(XmlNames.AttributeNames.DefaultName, "Notifications"),
new XElement(XmlNames.NodeNames.Subscriptions,
new XElement(XmlNames.NodeNames.Subscription,
new XAttribute(XmlNames.AttributeNames.ID, "7"),
new XAttribute(XmlNames.AttributeNames.DefaultName, "Subscriptions"))))));
return menu;
}
I put breakpoints before, on and after the method call as well as inside of the method. If I run the application, I can debug right through the method. But when I run some test cases, that cover this bit of code, they method call is never entered. Instead, the code equals navigationView to null. I fixed this by putting the method's code in the first class, but I'd like to know why this is an issue.
EDIT
Here is the code of one of the test cases that causes the faulty behavior when tested.
[TestMethod]
public void GetProductDetailNavigationModel_ProductWith3FieldValuesAnd2Documents_MappedObjectIsNotNull()
{
// Arrange
DDSInterfaceBlock.Current.IsImpersonated = false;
Domain.Supplier supplier = new Domain.Supplier().Init();
Domain.User user = new Domain.User().Init().Create();
Domain.Language language = new Domain.Language().Init();
Domain.Product product = new Domain.Product().Init().LinkSupplier(supplier);
Domain.ProductOverview.ProductDetail productDetail = ArrangeProductDetailData(supplier, user, language, product);
XDocument document = ArrangeXDocument(productDetail);
ProductDetail svc = new ProductDetail();
IProduct bus = MockRepository.GenerateStub<IProduct>();
bus.Stub(t => t.GetProductNavigationXDocument(supplier.Id, null, string.Empty))
.IgnoreArguments()
.Return(document);
bus.Stub(t => t.GetProductDetail(supplier.Id, user.Id, product.Id, language.Id, language.Id))
.IgnoreArguments()
.Return(productDetail);
svc.ProductBUS = bus;
svc.UserBUS = MockRepository.GenerateMock<BUS.Interfaces.IUser>();
svc.UserBUS
.Stub(t => t.CheckIfUserInPRAGroup(Guid.Empty))
.IgnoreArguments()
.Return(false);
// Act
Domain.ProductOverview.ProductDetailNavigationModel result
= svc.GetProductDetailNavigationModel(supplier.Id, user.Id, product.Id, language.Id, language.Id);
// Assert
Assert.IsNotNull(result);
}
Could it be because you have a stub for GetProductNavigationXDocument, but there is not sub for AddOptionsToNavigationMenu

How to run WebServices in a unit test

I created a function that verifies some rules. The function is supposed to return a bool whenever an element of a list matches an element of another list.
Here is the relevant code of the Rule Class
public override TestResult Execute()
{
Instrument ins = (Items.Length > 0) ? Items[0] as Instrument : null;
string errorInfo;
if (ins == null)
{
Result.Message = "Unable to perform test";
Result.Status = ResultStatus.Error;
return Result;
}
if (MPICSupportDB(ins))
{
Result.Message = "DB not supported by MPIC";
Result.Status = ResultStatus.Yellow;
}
else
{
Result.Status = ResultStatus.Green;
}
return Result;
}
private bool MPICSupportDB(Instrument ins)
{
IServiceProviderFactory serviceFactory = new WebServiceProviderFactory();
IInterfaceAssignmentService wService = serviceFactory.CreateInterfaceAssignmentService();
InterfaceAssignment wAssignments = wService.LoadAssignmentGroup("R4");
return ins.Connections.OfType<InterfaceConnection>()
.Where(conn => conn.Card.IsDB)
.Any(conn => wAssignments.PartMasters
.Any(partNumber => (conn.CardPartNumber == partNumber.PartNumber)));
}
I am trying to test the function MPICSupportDB in a unit test. So far I have started creating my unit test (below), but now I'm lost and I have no idea what to do.
[TestMethod]
public void TestForcompatibleDB()
{
var ins = new Instrument();
var serviceFactoryMock = new Mock<IServiceProviderFactory>();
var wserviceTest = new Mock<IInterfaceAssignmentService>();
var wassagnementTest = new Mock<InterfaceAssignment>();
// adding an MPIC card
ins.Connections.Add(AddCard(CardType.MPIC, "MA505400612268", "CARD1", 0, ins));
// adding an MPIC daughterboard
ins.Connections.Add(AddCard(CardType.GPIM_DB, "MA335022012268", "DB1", 1, ins));
var rule = new Rule026(RuleApplicability.Test, new object[] { ins });
var result = rule.Execute();
Assert.IsNotNull(result);
Assert.AreEqual(ResultStatus.Green, result.Status);
}
The problem is that classes like Webservice and factoryService cannot be run directly in a unit test.
Can someone explain to me how to properly mock these object and make my test run?
You need to provide the IServiceProviderFactory to your Rule026 class, rather than constructing it within the class. This will allow you to use your Mocks that you're creating. The most common approach would be through constructor injection. You haven't provided the Constructor for your Rule class, but if you modify it to something like this:
public Rule026(/*otherArgs*/, IServiceProviderFactory scpFactory = null) {
if(null == scpFactory)
scpFactory = new ServiceProviderFactory();
}
_serviceProviderFactory = scpFactory;
}
Then you will be able to inject the factory from your tests, whilst not having to update all of the code currently constructing Rules. Moving to an IOC container to provide the dependencies, or removing the default and forcing the clients to create the factory in order to able to instantiate the Rule may be preferable, depending on your situation.
Once you can pass in your mocks, you just need to setup a return chain to allow the mocks to return each other. Something like:
var serviceFactoryMock = new Mock<IServiceProviderFactory>();
var wserviceTest = new Mock<IInterfaceAssignmentService>();
var wassagnementTest = new Mock<InterfaceAssignment>();
serviceFactoryMock.Setup(x=>x.CreateInterfaceAssignmentService())
.Returns(wserviceTest.Object);
wserviceTest.Setup(x=>x.CreateInterfaceAssignmentService())
.Returns(wassagnementTest.Object);
wassagnementTest.Setup(x=>x.LoadAssignmentGroup(It.IsAny<string>()))
.Returns(cannedInterfaceAssignmentResponse);
And then supply the mock when constructing your object:
var rule = new Rule026(RuleApplicability.Test,
new object[] { ins },
serviceFactoryMock.Object);
You may also want to add verification etc to your mocks, depending on what you're trying to test and your particular style of testing.

How to evaluate local variable/ parameter state with Roslyn

I have a bit of complicated situation. I must create analyzers/ code fix providers for situations such as a parameter is only assigned but never used or local variable are never used.
For the parameter situation, I'm going for the method declaration and looking at the parameter list to get all the analyzer. I'm going through assignment expressions within the method and I filter the parameters that were assigned with an helper method.
Where it gets fuzzy is I have no clue or to know when a local variable/parameter is used or not. I've gone through symbols but they can't tell me that variable used/ not used. I could try to find how many times a variable's name was mentioned inside a method by turning the method declaration syntax context in a string and look for the parameters that were assigned but that's simply such a BAD idea.
I'm really stuck and I would some help for this from anyone who had previous experience with this kind of situation.
For people who might ask, I'm mostly looking for the missing logic for the analyzer. I have no idea how the code fix provider will work. If you have an idea of what I could do, feel free to include it in your answer ! As of now, I was thinking that a local variable that's not used could be deleted from a method and the same could go for an unused parameter. I'm not sure at the moment.
UPDATE
I'm now trying to use the DataFlow API but it's not working for me at the moment. The oldest answer of this thread gave me a starting point but it's actually not working.
I came up with my own way :
private static bool IsLocalVariableBeingUsed(VariableDeclaratorSyntax variableDeclarator, SyntaxNodeAnalysisContext syntaxNode)
{
var model = syntaxNode.SemanticModel.Compilation.GetSemanticModel(variableDeclarator.SyntaxTree);
var methodBody = variableDeclarator.AncestorsAndSelf(false).OfType<MethodDeclarationSyntax>().First();
var lastMethodNode = methodBody?.ChildNodes().LastOrDefault();
if (lastMethodNode == null)
return false;
var readWrite = syntaxNode.SemanticModel.AnalyzeDataFlow(variableDeclarator, lastMethodNode);
}
But this also is not working. When using a test with NUnit :
var input = #"
class TestClass {
void TestMethod ()
{
int i;
}
}";
I get the following message when the runtime gets to either readWrite or result(from oldest answer):
System.ArgumentOutRangeException Index was out of range Must be non negative and lesser than the size of the collection"
But before that in my analyzer, when I try to validate my node to make sure it's not null and create the appropriate elements for the data flow API, there's no code break (not sure if that is the appropriate term) but at the moment I cannot progress.
You can see whether or not most variable are used (read/written) via the DataFlowAnalysis APIs. I've written an introduction to this API on my blog.
I believe in your case, you're looking for variables that are never read.
var tree = CSharpSyntaxTree.ParseText(#"
public class Sample
{
public void Foo()
{
int unused = 0;
int used = 1;
System.Console.Write(used);
}
}");
var Mscorlib = PortableExecutableReference.CreateFromAssembly(typeof(object).Assembly);
var compilation = CSharpCompilation.Create("MyCompilation",
syntaxTrees: new[] { tree }, references: new[] { Mscorlib });
var model = compilation.GetSemanticModel(tree);
var methodBody = tree.GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().Single().Body;
DataFlowAnalysis result = model.AnalyzeDataFlow(methodBody);
var variablesDeclared = result.VariablesDeclared;
var variablesRead = result.ReadInside.Union(result.ReadOutside);
var unused = variablesDeclared.Except(variablesRead);
foreach(var variable in unused)
{
Console.WriteLine(variable);
}
Building on JoshVarty's answer, to get this to work in a diagnostic, I would register a SyntaxNodeAction for all MethodDeclaration Syntax Kinds and then look inside the body for unused variables:
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction(AnalyzeIt, SyntaxKind.MethodDeclaration);
}
private static void AnalyzeIt(SyntaxNodeAnalysisContext context)
{
var method = context.Node as MethodDeclarationSyntax;
var dataFlow = context.SemanticModel.AnalyzeDataFlow(method.Body);
var variablesDeclared = dataFlow.VariablesDeclared;
var variablesRead = dataFlow.ReadInside.Union(dataFlow.ReadOutside);
var unused = variablesDeclared.Except(variablesRead);
if (unused.Any())
{
foreach (var unusedVar in unused)
{
context.ReportDiagnostic(Diagnostic.Create(Rule, unusedVar.Locations.First()));
}
}
}

Mocking SPServer.Local

I want to be able to mock the object that is returned by SPServer.Local but I can't seem to do it in typemock. At the moment when I debug, I see that SPServer.Local returns a null object of type SPServer. Shouldn't typemock be swapping out this instance with my fake instance? Is there something I'm doing wrong? The code runs fine on the sharepoint server.
[TestInitialize]
public void Setup()
{
fakeSite = Isolate.Fake.Instance<SPSite>(Members.ReturnRecursiveFakes);
Isolate.Swap.NextInstance<SPSite>().With(fakeSite);
fakeServer = Isolate.Fake.Instance<SPServer>(Members.ReturnRecursiveFakes);
Isolate.Swap.NextInstance<SPServer>().With(fakeServer);
sharePointStorageRepository = new SharePointStorageRepository();
}
[TestMethod]
[Isolated]
public void CreateHRFolderMethodCreatesHRFolder()
{
// arrange
// some arrange logic here
// act
var actual = sharePointStorageRepository.Create();
// assert
Assert.AreEqual(expected, actual);
}
This is the bit of code that is being run:
internal static Guid GetSiteGuid(string serverRelativeUrl, string webApplicationName)
{
Guid? guid = null;
SPServer myServer = SPServer.Local;
foreach (var serviceInstance in myServer.ServiceInstances.Where(si => si.Service is SPWebService)){
var service = (SPWebService) serviceInstance.Service;
var webapp = service.WebApplications.SingleOrDefault(wa => wa.DisplayName == webApplicationName);
if (webapp != null){
var site = webapp.Sites.SingleOrDefault(wa => wa.ServerRelativeUrl == serverRelativeUrl);
if (site != null) guid = site.ID;
}
}
if (!guid.HasValue){
throw new FileNotFoundException(
String.Format(
"Cannot find Site Collection with WebApplication \"{1}\" and ServerRelativeUrl \"{2}\" running on \"{0}\"",
myServer.Address, webApplicationName, serverRelativeUrl));
}
return guid.Value;
}
Thanks all!
I don't work in SharePoint, but something I noticed: You're not actually mocking the return of SPServer.Local anywhere. I think that's the missing step. I'm also not entirely sure you need to SwapNextInstance since I don't see anywhere that is actually creating an SPServer object.
That would change your test code to:
[TestInitialize]
public void Setup()
{
// I don't see where you're using SPSite, so I assume it's in code
// not being shown; otherwise you can remove this.
fakeSite = Isolate.Fake.Instance<SPSite>(Members.ReturnRecursiveFakes);
Isolate.Swap.NextInstance<SPSite>().With(fakeSite);
fakeServer = Isolate.Fake.Instance<SPServer>(Members.ReturnRecursiveFakes);
// INSTEAD OF THIS: Isolate.Swap.NextInstance<SPServer>().With(fakeServer);
// DO THIS:
Isolate.WhenCalled(() => SPServer.Local).WillReturn(fakeServer);
sharePointStorageRepository = new SharePointStorageRepository();
}
That WhenCalled method will mean that any time anyone asks for SPServer.Local, it'll return your fake instance.
Note that I see in the code being tested that you get the ServerInstances property. I don't see any specific return values getting set up, so I assume you're controlling the rest of the stuff in the omitted "arrange" logic.

Categories

Resources