How to create an Azure.AsyncPageable for mocking? - c#

I would like to mock a C# method that returns an Azure.AsyncPageable.
This class has only protected constructors, so I cannot instantiate it directly. Is there any way to create an instance of this class from some other collection, such as an IAsyncEnumerable or just a List?

You can create Page objects using Page<T>.FromValues.
Then, create a AsyncPageable<T> using AsyncPageable<T>.FromPages.
Example:
var page = Page<TableEntity>.FromValues(new List<TableEntity>
{
new TableEntity("1a", "2a"),
new TableEntity("1", "2b")
}, continuationToken: null, new Mock<Response>().Object);
var pages = AsyncPageable<TableEntity>.FromPages(new[] { page });

Related

C# How to make one class instance available to another class method

I have this:
Crew_Photos photos = new Crew_Photos(); // contains List<t> of photos
Bus_Crew buscrew = new Bus_Crew(); // Calls update.AddUpdate()
Cab_Crew cabcrew = new Cab_Crew(); // Also calls update.AddUpdate()
UpdateCrew update = new UpdateCrew(); // DEFINES method AddUpdate();
I'm trying to avoid doing this:
Crew_Photos photos = new Crew_Photos();
Bus_Crew buscrew = new BusDriver_Crew(photos);
busscrew.AddUpdate(photos);
Cab_Crew cabcrew = new Cab_Crew(photos);
cabcrew.AddUpdate(photos);
UpdateCrew update = new UpdateCrew(photos);
I do not want to pass photos to Bus_Crew, and Cab_Crew, only so that I can then pass it again to UpdateCrew() which is actually going to use it.
How can I make Crew_Photos photos available to update.AddUpdate() when it is called by buscrew.AddUpdate() and cabcrew.AddUpdate()?
How about a constructor for UpdateCrew that receives the three things?
UpdateCrew update = new UpdateCrew(new Crew_Photos(), new BusDriver_Crew(), new Cab_Crew());
Then the constructor can call AddUpdate() internally?
It's not clear what is happening within the different classes, so answering this question is very difficult.

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

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);

Call a common function from a list of objects [duplicate]

This question already has answers here:
Return one of two possible objects of different types sharing a method
(6 answers)
Closed 5 years ago.
I am trying to create a Proxy Scraper. For each website I have, I try to scrape the proxies. The scrape code for each website is in a class with the name of the website.
For example:
I have the websites "wwww.proxy.com and www.moreproxy.com"
I have 2 classes: Proxy and MoreProxy with the functions "scrape" that varies for both (since they are different websites).
To get the lists, I do something like this:
//The below code doesn't exist, but just to get my point across
//Each datagrid.Add is in a separate thread
datagrid.Add(new Proxy().scrape());
datagrid.Add(new MoreProxy().scrape());
datagrid.Add(...);
datagrid.Add(...);
//And so on for all the other websites I might add...
Now is there a way to loop this? I was trying something like this, but it does not work:
List<object> objects = new List<object>();
objects.Add(new Proxy(), new MoreProxy(), ..., ...); //I can update this each time I add a new website
foreach(object o in objects)
{
datagrid.Add(o.scrape());
}
The scrape function looks something like this:
public List<string[]> scrape()
{
HtmlDocument PageContent = new HtmlWeb().Load("https://free-proxy-list.net/");
HtmlNode[] nodes = PageContent.DocumentNode.SelectNodes("//td").ToArray();
List<string[]> proxies = new List<string[]>();
for (int i = 0; i < nodes.Length; i += 8)
{
string[] proxy = { nodes[i].InnerHtml, nodes[i + 1].InnerHtml };
proxies.Add(proxy);
}
return proxies;
}
Does something like this exist? Basically I have several classes with a common function scrape. I want to create a list of all these classes as objects, and execute the function scrape. How would I do that (solution needs to be thread safe)
Setup an interface:
public interface IScrape()
{
object Scrape();
}
Have your proxy classes implement the interface:
// repeat for Proxy
public class MyProxy : IScrape{
object Scrape()
{
return something;
}
}
then
List<IScrape> objects = new List<IScrape>();
objects.Add(new Proxy(), new MoreProxy(), ..., ...); //I can update this each time I add a new website
foreach(IScrape o in objects)
{
datagrid.Add(o.Scrape());
}
Interfaces are the problems solution.
Like this:
public interface IScrapable {
void Scrape();
}
public class Proxy : IScrapeable {
public void Scrape() { ...}
}
Now you can Loop and scrape your objects.
List<IScrapable> objects = new List<IScrapable>();
objects.Add(new Proxy(), new MoreProxy(), ..., ...); //I can update this each time I add a new website
foreach(IScrapable o in objects)
{
datagrid.Add(o.scrape());
}
This should do what you want.

Initialize nested classes in a list

I have a list called OrderProductAttributes and I initialzed it like the following:
OrderProductAttributes = new List<OrderProductAttribute>
{orderProductAttribute }
I have to two other nested classes in the OrderProductAttribute and I am trying to instantiate them like the following:
static OrderProductAttribute orderProductAttribute = new OrderProductAttribute()
{
productAttribute = new ProductAttribute()
{
attributeType=new AttributeType()
}
};
I want to see them as a json file and once I open the output json file I see the following:
"OrderProductAttributes":{"["productAttribute":null]"}
I was wondering why the attributeType was not created in the productAttribute since I have initiated it already?
I was expecting to see
"OrderProductAttributes":{"["productAttribute":"attributeType":""]"}

dynamic method and the MethodAccessException

given the following classes:
class SomeBuilder<T>
{
public static object Build(int index)
{
...
}
}
class SomeHelper
{
public object GetBuildObj(object value)
{
var valuetype = value.GetType();
var methodinfo = typeof(SomeBuilder<>).MakeGenericType(valuetype).GetMethod("Build");
var handler = SomeDynamicHelper.GetMethodInvoker(methodinfo);
var result = hander(null, new object[]{1});
}
}
SomeBuilder was a generic type so i need a call to MakeGenericType() to make things right.
when i pass a normal type like 'class person' for the value, everything just works, that`s fine.
but when i pass a anonymous type like: new { id=1 }, the handler was successfully created. but invoke this dynamic handler i got a MethodAccessException with these messages:
"method "SomeDynamicHelper.(System.Object, System.Objec[])" try to access method "SomeBuilder'1<<>f__AnonymousType0'1<System.Int32>>.Build(int)" failed.
any help would be appreciated, thx.
btw, if you are interested in SomeDynamicHelper, plz see:
http://www.codeproject.com/Articles/14593/A-General-Fast-Method-Invoker
edit1:
i did the call in main like this:
static void Main(string[] args)
{
// pass a normal class, this will be fine
var value = new Person { id = 1};
new SomeHelper().GetBuildObj(value);
// pass a anonymous type
var value = new { id = 1};
new SomeHelper().GetBuildObj(value); // oops, got a exception here!
}
edit2:
based on the comment i changed my code:
class SomeHelper
{
public object GetBuildObj(object value)
{
//this time i do not use the value, but create a new inner value:
var valuenew = new { id = 1 };
var valuetype = valuenew.GetType();
var methodinfo = typeof(SomeBuilder<>).MakeGenericType(valuetype).GetMethod("Build");
var handler = SomeDynamicHelper.GetMethodInvoker(methodinfo);
var result = hander(null, new object[]{1});
}
}
well, this time there is no exception, but...unfortunately a new problem occured...may be i should open a new thread for the new problem.
thank you guys, for your attentions.
edit3:
hi, after some digging, i also found some useful information. say, the SomeDynamicHelper.GetMethodInvoker() code as below:
DynamicMethod dynamicMethod = new DynamicMethod(string.Empty, typeof(object), new Type[] { typeof(object), typeof(object[]) }, methodInfo.DeclaringType.Module);
this is the core we used here to dynamic create a method. for our context, we need to declare the anonymous type in same assembly with the SomeHelper and SomeBuilder. but, if we can`t do the declaration, what should we do?
ok, you can call DynamicMethod() with last parameter(the skipVisibility), set to true!
hope this will help others with the same problem :)
"method "SomeDynamicHelper.(System.Object, System.Objec[])" try to access method "SomeBuilder'1<<>f__AnonymousType0'1>.Build(int)"
From this you can see that dynamic method try to run an internal\private method called Build, for that you got MethodAccessException.
(The anonymous type is kept in a new generated class)
Adding InternalVisibleTo not always helping because it's helping only if you can rewrite the anonymous type assembly (manually or with interception) and only if the type and method are internals and not private.
In dynamic method you can bind the method to type\module, and to skip visibility check, but this help to access private members of the specified module, so again if the type you trying to access is in a different assembly and the type\method are private you can't do anything.
Well almost. There is a "secret" attribute that you inject to your assembly, called IgnoreAccessChecksTo and then in addition to bounded module and skip visibility maybe it will work.
You can try using [assembly: InternalsVisibleTo("Anonymously Hosted DynamicMethods Assembly")] in the same project where you define the anonymous type.
I had a similar error with a C# class I tried to inject using IKVM-converted Guice. The fix was simply making the affected class (in this case probably SomeBuilder) public and everything worked fine.

Categories

Resources