Xunit Parameterize Selenium By Type - selenium

I have asked several basic questions related to this in the past and got great answers that explained several issues. I think i'm now in a position to ask the correct question now that I'm more aware of how Xunit works!
I am trying to parametrize several tests in C# using visual studio. I need each parameter to be displayed as an individual test that can be ran in isolation if required (I know there is a test collection runner and a separate test runner). The test collection runner is my issue.
I know that Xunit requires the parameters to be serialized in order for them to be picked up by the test collection runner. I also know that it by default can easily serialize basic data types like string, bool, int etc.
I have tried various approaches to do this with mixed results. My issue is trying to parameterize the Selenium type 'By'. I can't seem to be able to serialize this. I've tried to trick Xunit for example by using a dictionary List<string, By> and trying to serialize the in the dictionary (no luck!)
Here is the cleanest code I have come across that is simple and elegant for what i'm trying to do, but again I can't serialize the 'By' type. I have played around with changing the static property from bool to By and it returns only 1 test for all params, so it's not being serialized
public class ParamTest1
{
static string test3 = "TestXYZ";
public static TheoryData<int, bool, string, string> DataForTest1 = new TheoryData<int, bool, string, string>
{
{ 1, true, "First", test3 },
{ 2, false, "Second", test3},
{ 3, true, "Third", test3}
};
[Theory(DisplayName = "My First Test"), MemberData(nameof(DataForTest1))]
public void Test1(int valA, bool valB, string valC, string valD)
{
Assert.True(valB);
}
}
Which gives me
I am aware this particular code isn't invoking the IXunitSerializable
So here is an another working example of what I need but I just can't get it to work with the 'By' Type
public class ValidateTestCase : IXunitSerializable
{
public Guid Coupon { get; set; }
public bool IsValid { get; set; }
public void Serialize(IXunitSerializationInfo info)
{
info.AddValue(nameof(Coupon), Coupon.ToString());
}
public void Deserialize(IXunitSerializationInfo info) { }
}
public class Testing
{
public static IEnumerable<object[]> ValidateTestCases
{
get
{
yield return new object[] { new ValidateTestCase { Coupon = Guid.Parse("73e4d185-70cf-4ce4-bc3f-187b7a40e167"), IsValid = false } };
yield return new object[] { new ValidateTestCase { Coupon = Guid.Parse("93b983fb-5b6a-4845-a769-db41900b7df9"), IsValid = false } };
yield return new object[] { new ValidateTestCase { Coupon = Guid.Parse("99c03283-33cb-4e56-a010-c2bc0758ad27"), IsValid = false } };
yield return new object[] { new ValidateTestCase { Coupon = Guid.Parse("16a7fe80-3111-44b0-9ebf-c7159bea637d"), IsValid = false } };
yield return new object[] { new ValidateTestCase { Coupon = Guid.Parse("8b38b4aa-d70f-4ce7-8992-8a60936c5c58"), IsValid = false } };
yield return new object[] { new ValidateTestCase { Coupon = Guid.Parse("abc60aa0-a33b-4057-8f99-5cdceda35c70"), IsValid = true } };
}
}
[Theory(DisplayName = "CouponService should validate coupons")]
[MemberData(nameof(ValidateTestCases))]
public void MyCouponService_Validates(ValidateTestCase vtc)
{
Assert.Equal(vtc.IsValid, true);
}
}
And finally for anyone wondering what the 'By' type is I am referring to it's :
[![enter image description here][2]][2]
Here it is in the debugger so you can see what's going on inside:
[![enter image description here][3]][3]
I know there's a lot going on in there but if anyone has any ideas or suggestions it would be great!
To summarize, I can't parameterize the Selenium 'data type' By.
[2]: https://i.stack.imgur.com/XcLcn.png
[3]: https://i.stack.imgur.com/T9so1.png

Serializing Class
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Text;
using OpenQA.Selenium;
using Xunit.Abstractions;
namespace XUnitTestProject1
{
public class ParameterizedHook
{
public By p1 { get; set; }
public By p2 { get; set; }
public string assertion { get; set; }
}
public class TheoryWrapper<T> : IXunitSerializable
{
public TheoryWrapper(string label, T #object)
{
Name = label;
Object = #object;
}
public TheoryWrapper()
{
}
public string Name { get; set; }
public T Object { get; set; }
public void Deserialize(IXunitSerializationInfo info)
{
Name = info.GetValue<string>("Label");
Object = JsonConvert.DeserializeObject<T>(info.GetValue<string>("objValue"));
}
public void Serialize(IXunitSerializationInfo info)
{
info.AddValue("Label", Name, typeof(string));
var json = JsonConvert.SerializeObject(Object);
info.AddValue("objValue", json);
}
public override string ToString()
{
return Name;
}
}
}
Working Test
public static IEnumerable<object[]> ComplexTheoryData
{
get
{
return new List<object[]>
{
new object[] {0, new TheoryWrapper<ParameterizedHook>("Pass0", new ParameterizedHook { p1 = nav_hold.pip_builder.dash_expand_pip_builder_menu, p2 = nav_hold.pip_builder.dash_project_stages, assertion = "WORK STAGE" })},
new object[] {0, new TheoryWrapper<ParameterizedHook>("Pass0", new ParameterizedHook { p1 = nav_hold.pip_builder.dash_expand_pip_builder_menu, p2 = nav_hold.pip_builder.dash_project_stages, assertion = "WORK STAGES" })},
//new object[] {0, new TheoryWrapper<ParameterizedHook>("Pass0", new ParameterizedHook { TestData = b.login })},
//new object[] {1, new TheoryWrapper<ParameterizedHook>("Pass1", new ParameterizedHook { TestData = b.password })}
};
}
}
[SkippableTheory]
[Trait("xUnit", "ForTestRunner")]
[MemberData(nameof(ComplexTheoryData))]
public void Test_Navigation(int id, TheoryWrapper<ParameterizedHook> test)
{
nav_met.NavMethodTest(test.Object.p1, test.Object.p2);
By page_title = By.Id("ctl00_lblPageTitle");
Assert.True(nav_met.VerifyText(page_title, test.Object.assertion));
}

Related

How to send Collection of abstract types with ActionResult

I am trying to send back a collection of abstract types in a Controller using ActionResult.I do not know how to tell the serializer to also include derived type(s) specific properties:
public abstract class Base
{
public int Id{get;set;}
}
public class D1:Base
{
public string D1Value{get;set;}
}
public class D2:Base
{
public bool IsD2Value{get;set;}
}
public async Task<ActionResult<IEnumerable<Base>>> GetAll()
{
var collection=new []{ new D1 { Id=1, D1Value="hi"} ,new D2 {Id=2, IsD2Value=true}};
return StatusCode(200,collection);
}
How can i reach this result in a easy and elegant way.I have checked the JsonSerializer options but in my case i am not the one that is doing the serialization.
What i get
[{ "Id":1} , { "Id":2 }]
What i want
[{ "Id":1,"D1Value":"hi" } , { "Id":2 , "IsD2Value":true }]
Try the following code:
public async Task<ActionResult<IEnumerable<Base>>> GetAll()
{
var collection = new List<object>()
{
new D1 { Id = 1, D1Value = "hi" },
new D2 { Id = 2, IsD2Value = true }
};
return StatusCode(200, collection);
}
Here is the test result:
Use new ArrayList() instead of List.

Value type field required in Razor View

I have an enum type field called Title.
[Serializable]
public enum Title
{
NotSet,
Miss = 4,
Mr = 1,
Mrs = 3,
Ms = 2
}
I want to bind a property of type Title to the Razor View but I don't want it to be a required field. However, on tabbing out or OnBlur, it is showing as required, although I have not specified this as required.
Is there any way I can get around this?
create
namespace YourApplicationName.Helper
{
public class ModelValueListProvider : IEnumerable<SelectListItem>
{
List<KeyValuePair<string, string>> innerList = new List<KeyValuePair<string, string>>();
public static readonly ModelValueListProvider TitleList = new TitleListProvider();
protected void Add(string value, string text)
{
string innerValue = null, innerText = null;
if (value != null)
innerValue = value.ToString();
if (text != null)
innerText = text.ToString();
if (innerList.Exists(kvp => kvp.Key == innerValue))
throw new ArgumentException("Value must be unique", "value");
innerList.Add(new KeyValuePair<string, string>(innerValue, innerText));
}
public IEnumerator<SelectListItem> GetEnumerator()
{
return new ModelValueListProviderEnumerator(innerList.GetEnumerator());
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
private struct ModelValueListProviderEnumerator : IEnumerator<SelectListItem>
{
private IEnumerator<KeyValuePair<string, string>> innerEnumerator;
public ModelValueListProviderEnumerator(IEnumerator<KeyValuePair<string, string>> enumerator)
{
innerEnumerator = enumerator;
}
public SelectListItem Current
{
get
{
var current = innerEnumerator.Current;
return new SelectListItem { Value = current.Key, Text = current.Value };
}
}
public void Dispose()
{
try
{
innerEnumerator.Dispose();
}
catch (Exception)
{
}
}
object System.Collections.IEnumerator.Current
{
get
{
return Current;
}
}
public bool MoveNext()
{
return innerEnumerator.MoveNext();
}
public void Reset()
{
innerEnumerator.Reset();
}
}
private class TitleListProvider : ModelValueListProvider
{
public TitleListProvider (string defaultText = null)
{
if (!string.IsNullOrEmpty(defaultText))
Add(string.Empty, defaultText);
Add(Title.NotSet, "NotSet");
Add(Title.Miss , "Miss");
Add(Title.Mr , "Mr");
Add(Title.Mrs , "Mrs");
Add(Title.MS, "MS");
}
public void Add(Title value, string text)
{
Add(value.ToString("d"), text);
}
}
}
}
in your model
public Title? Titleformation { get; set; }
public string[] SelectedTitle { get; set; }
in your view, also add the name space to your view
#using YourApplicationName.Helper;
#Html.ListBoxFor(m => m.SelectedTitle , new SelectList(ModelValueListProvider.TitleList, "Value", "Text"))
hope this help you
Enums require values, and cannot be null (aka not set) despite what someone commented above. What I do for salutations is have a "none" member of the enum, and whenever I print this out, I just check in the code to see if the value of the enum is > 0 (aka, the none option) and don't print it.
public enum Salutation { none,
[Description("Mr.")] Mr,
[Description("Mrs.")] Mrs,
[Description("Ms.")]Ms,
[Description("Miss")] Miss }
Use a class rather than enum ie:
public class Title
{
NotSet;
Miss = 4;
Mr = 1;
Mrs = 3;
Ms = 2;
}

RavenDB static index on dictionary

I have an application that uses documents, that contain list of attributes in a dictionary, for some reason we need to use a static index and query/filter over these attributes.
A prototype looks like this:
class Program
{
static void Main(string[] args)
{
IDocumentStore store = new DocumentStore() { DefaultDatabase = "Test", Url = "http://localhost:8081" };
store.Initialize();
IndexCreation.CreateIndexes(typeof(Program).Assembly, store);
using (var session = store.OpenSession())
{
session.Store(new Document { Id = "1", Name = "doc_name", Attributes = new Dictionary<string, object> { { "Type", "1" }, { "Status", "Active" } } });
session.SaveChanges();
}
using (var session = store.OpenSession())
{
// works
var l1 = session.Query<Document, Documents_Index>().Where(a => a.Attributes["Type"] == "1").ToList();
// not working
var l2 = session.Query<Document, Documents_Index>().Where(a => a.Attributes["Status"] == "Active").ToList();
}
}
}
public class Documents_Index : AbstractIndexCreationTask<Document>
{
public Documents_Index()
{
Map = docs => docs.Select(a =>
new
{
a.Name,
a.Attributes,
Attributes_Type = a.Attributes["Type"]
});
}
}
[Serializable]
public class Document
{
public string Id { get; set; }
public string Name { get; set; }
public Dictionary<string, object> Attributes { get; set; }
}
But since I need to query using any arbitrary Attribute name/value this index does solve our problem. Actually the list of attributes is known at run-time (so we tried modifying the Map expression to inject any number of attribute names, but so far we weren't successful). Is there a way how to define the index in some dynamic fashion?
You need to write it like:
public class Documents_Index : AbstractIndexCreationTask<Document>
{
public Documents_Index()
{
Map = docs => docs.Select(a =>
new
{
a.Name,
_ = a.Attributes.Select(x=>CreateField("Attributes_"+x.Key, x.Value),
});
}
}

AsProjection() throwing exception for async query

In a simple test scenario which can be setup using the following:
public class TestObj
{
public string Id { get; set; }
public string Name { get; set; }
}
public class Summary
{
public string MyId { get; set; }
public string MyName { get; set; }
}
public class TestObjs_Summary : AbstractIndexCreationTask<TestObj, Summary>
{
public TestObjs_Summary()
{
Map = docs => docs.Select(d => new { MyId = d.Id, MyName = d.Name });
Store(x => x.MyId, FieldStorage.Yes);
Store(x => x.MyName, FieldStorage.Yes);
}
}
static IDocumentStore Setup()
{
var store = new DocumentStore() { Url="http://localhost:8080" };
store.Initialize();
IndexCreation.CreateIndexes(MethodInfo.GetCurrentMethod().DeclaringType.Assembly, store);
using (var session = store.OpenSession())
{
session.Store(new TestObj { Name = "Doc1" });
session.Store(new TestObj { Name = "Doc2" });
session.SaveChanges();
}
return store;
}
I can run a simple synchronous query against the index and get the expected results (2 rows output of type Summary):
using (var session = store.OpenSession())
{
var q = session.Query<Summary>("TestObjs/Summary").AsProjection<Summary>();
Dump("Sync:", q.ToList());
}
However, if I try the same thing using an asynchronous query:
using (var session = store.OpenAsyncSession())
{
var q = session.Query<Summary>("TestObjs/Summary").AsProjection<Summary>();
q.ToListAsync().ContinueWith(t => Dump("Async:", t.Result));
}
I get an InvalidCastException:
InnerException: System.InvalidCastException
Message=Unable to cast object of type 'TestObj' to type 'Summary'.
Source=Raven.Client.Lightweight
StackTrace:
at Raven.Client.Document.InMemoryDocumentSessionOperations.ConvertToEntity[T](String id, RavenJObject documentFound, RavenJObject metadata) in c:\Builds\RavenDB-Unstable\Raven.Client.Lightweight\Document\InMemoryDocumentSessionOperations.cs:line 416
at Raven.Client.Document.InMemoryDocumentSessionOperations.TrackEntity[T](String key, RavenJObject document, RavenJObject metadata) in c:\Builds\RavenDB-Unstable\Raven.Client.Lightweight\Document\InMemoryDocumentSessionOperations.cs:line 340
at Raven.Client.Document.SessionOperations.QueryOperation.Deserialize[T](RavenJObject result) in c:\Builds\RavenDB-Unstable\Raven.Client.Lightweight\Document\SessionOperations\QueryOperation.cs:line 130
...
I suspect this is a bug, but as a RavenDB newbie, I first wanted to rule out the possibility I have screwed something up here. Can anyone see why this code would be failing?
(Note: this was run on Build 721 and on 701 and both produce the same results)
Thanks for any assistance you can provide.
It looks like a bug. I don't see anything wrong in your code. I suggest you create an issue here: http://issues.hibernatingrhinos.com

Serializing object graph using MongoDB Bson serializer

I've been playing a little with the MongoDB Bson serializer, using the following piece of code:
class Program
{
public class myValue
{
public int Id = 0;
public string Label = "";
}
public class myValueMap : Dictionary<string, myValue>
{
}
public class myProdData
{
public myValueMap Mapping { get; set; }
}
public class mySystemPosition
{
public string Text { get; set; }
public myProdData ProdData { get; set; }
}
static void Main(string[] args)
{
BsonClassMap.RegisterClassMap<mySystemPosition>();
BsonClassMap.RegisterClassMap<myProdData>();
BsonClassMap.RegisterClassMap<myValueMap>();
BsonClassMap.RegisterClassMap<myValue>();
var o = new mySystemPosition()
{
ProdData = new myProdData()
{
Mapping = new myValueMap()
{
{"123", new myValue() {Id = 1, Label = "Item1"}},
{"345", new myValue() {Id = 2, Label = "Item2"}},
}
}
};
var bson = o.ToBson();
var text = Encoding.ASCII.GetString(bson);
}
}
however I don't seem to be able to get the myProdData.Mapping serialized....
Do I need to configure the MongoDB Bson serializer in a special way, to make this work?
You no need to use BsonClassMap.RegisterClassMap if you no need custom serializtion(documentation).
All your classes will be desirialzied according to default rules.
Also i am changed your example a little bit to get it work(i've replaces myValueMap class with Dictionary):
public class myProdData
{
public Dictionary<string, myValue> Mapping { get; set; }
}
static void Main(string[] args)
{
var o = new mySystemPosition()
{
ProdData = new myProdData()
{
Mapping = new Dictionary<string, myValue>()
{
{"123", new myValue() {Id = 1, Label = "Item1"}},
{"345", new myValue() {Id = 2, Label = "Item2"}},
}
}
};
var json = o.ToJson();
Console.WriteLine(json);
Console.ReadKey();
}
Here is console output(just well formatted):
{
"Text":null,
"ProdData":{
"Mapping":{
"123":{
"_id":1,
"Label":"Item1"
},
"345":{
"_id":2,
"Label":"Item2"
}
}
}
}
You can test your serializtion using ToJson() extention method, in order to view that all correct and after that use ToBson() if need.
The problem is that myValueMap derives from Dictionary. That results in a class that the AutoMap method can't handle.
I recommend you just use the Dictionary directly, as Andrew did in his reply.
Ufortunately the myValueMap is an object that I can't easily change, however it turns out, that's pretty easy to create your own (de)serializer....
public class myValueMapSerializer : IBsonSerializer
{
public object Deserialize(Bson.IO.BsonReader bsonReader, System.Type nominalType, System.Type actualType, IBsonSerializationOptions options)
{
if (nominalType != typeof(myValueMap)) throw new ArgumentException("Cannot serialize anything but myValueMap");
var res = new myValueMap();
var ser = new DictionarySerializer<string, myValue>();
var dic = (Dictionary<string, myValue>)ser.Deserialize(bsonReader, typeof(Dictionary<string, myValue>), options);
foreach (var item in dic)
{
res.Add(item.Key, item.Value);
}
return res;
}
public object Deserialize(Bson.IO.BsonReader bsonReader, System.Type nominalType, IBsonSerializationOptions options)
{
throw new Exception("Not implemented");
}
public bool GetDocumentId(object document, out object id, out IIdGenerator idGenerator)
{
id = null;
idGenerator = null;
return false;
}
public void Serialize(Bson.IO.BsonWriter bsonWriter, Type nominalType, object value, IBsonSerializationOptions options)
{
if (nominalType != typeof(myValueMap)) throw new ArgumentException("Cannot serialize anything but myValueMap");
var ser = new DictionarySerializer<string, myValue>();
ser.Serialize(bsonWriter, typeof(DictionarySerializer<string, myValue>), value, options);
}
public void SetDocumentId(object document, object id)
{
return;
}
}