I have written Page object class for Login page to test UI look & feel for web, iphone & tablet. For each verification I have written a method to return cssValue or text for that element.
Writing that increases lot method defined in a single class. Is there any way to reduce no of methods declared in a page object class?
Example:
public String getBannerCssValue(String cssValue){
return getCssValue(driver.findElement(banner), cssValue);
}
public String getSmartPhoneLegendText(){
return getElementText(driver.findElement(smartPhoneLegend));
}
public String getSmartPhoneLegendCssValue(String cssValue){
return getCssValue(driver.findElement(smartPhoneLegend), cssValue);
}
public String getTabletLegendText(){
return getElementText(driver.findElement(tabletLegend));
}
public String getTabletLegendCssValue(String cssValue){
return getCssValue(driver.findElement(tabletLegend), cssValue);
}
public String getButtonTextValue(){
return getAttribute(driver.findElement(login), "value");
}
public String getSubmitButtonCssValue(String cssValue){
return getCssValue(driver.findElement(login), cssValue);
}
public String getForgotPasswordCssValue(String cssValue){
return getCssValue(driver.findElement(forgotYourPassword), cssValue);
}
public String getTabButtonTextValue(){
return getAttribute(driver.findElement(tabletSubmit), "value");
}
I think you should be guided by the way you'll actually use these getters.
In my code, I often read a number of controls into a single object: user data on the page gets read into a User object. So I have a single getter for that.
In other contexts, where I don't have (or need) an object, I have individual getters for individual controls.
Are there setters for some or all of these getters? If so, consider merging a getter/setter pair into a single function. I've written about this on my blog:
Getters and Setters
Related
I have different configurations all inheriting from a base configuration that are customized in forms. I want all of these to be handled by a single action result.
[HttpPost]
public IActionResult Register(AbstractBaseConfig config)
{
...do some logic...
return View("../Home/Index");
}
However, this is not possible because you cannot base in abstract classes as a parameter to an action result. Is there any work around for this so I don't need a seperate action result for each configuration? (I still want each configuration to be it's own class, I only need access to the base class methods in the action result logic).
Basically you can't, and the reason is that MVC will try to do new AbstractBaseConfig() as part of the Data Binding process (which parses the URL or the Form Post and puts the results in a concrete object). And by definition, doing new AbstractBaseConfig() is impossible for an abstract class.
It also makes sense for other reasons, I will explain why.
You seem to expect that MVC can determine the class from the parameters that are being passed in. That is not how it works, in fact the opposite is true: the Action Method has to specify the exact class, and then the Binder will instantiate that exact class and try to bind its properties.
Suppose you had this:
public abstract class Thing { public int ID { get;set; } }
public class NamedThing : Thing { public string Name { get;set; } }
public class OtherThing : Thing { public string Name { get;set; } }
and suppose it would be allowed to use:
public IActionResult Register(Thing thing)
then what would you expect to be in thing after Data Binding: a Thing object with only the ID set? Or one of the other object types, with Name set, but how would MVC ever be able to know which class you meant?
So for all these reasons, this is not possible.
You could have a base class inherit the abstract class and all your classes inherit from that base class whilst having that base class as your parameter
Take for example
public abstract class ABase
{
public void stuff()
{
var stuff = string.Empty;
stuff = "hello";
}
public virtual void otherstuff()
{
var stuff = string.Empty;
stuff = "hello";
}
}
public class Base : ABase
{
//empty
}
public class Derived : Base
{
public void mystuff()
{
this.stuff();
}
public override void otherstuff()
{
// Custom code
}
}
public ActionResult Register(Base config)
{
}
I have an ApiController that returns OkNegotiatedContentResult<T> with a resource collection, paginated. Naturally, there will be more methods that return paginated collections.
The content in the result of all those actions looks roughly like this:
A Data property with the current items
A PagingMeta property with paging metadata such as total pages and total items
A PagingLinks property that contain links to first/prev/next/last pages
My backend returns a custom PagedList<T> object and I have another PagedListResponse<T> that contains the above properties. It's a simple transformation from one to the other.
Now, in Web API, the ApiController provides a couple of convenient methods for returning IHttpActionResult, such as:
Ok<T>(T value)
Content<T>(HttpStatusCode statusCode, T value)
I was hoping to make it just as easy for the controller to return a paged result just as easily.
For the moment I have an extension method that provides it, with the following signature:
public static OkNegotiatedContentResult<PagedListResult<T>> OkPaged<T>(this ApiController controller, /* other parameters */)
The "ugly" is that you can only call an extension method by including the this keyword:
return this.OkPaged(myResult);
the only other option I can see is to implement a base controller class, but I generally try to avoid such inheritance structures because they tend to get troublesome later down the road.
What does ASP.NET provide in terms of extension points to do what I want to do?
You can always create a class that inherits from IHttpActionResult and use that as your return value, e.g
public class HttpStatusCodeResultWithContent<T> : IHttpActionResult
{
private readonly HttpRequestMessage httpRequestMessage;
private readonly HttpStatusCode statusCode;
public HttpStatusCodeResultWithContent(HttpRequestMessage httpRequestMessage, HttpStatusCode statusCode, T model)
{
this.httpRequestMessage = httpRequestMessage;
this.statusCode = statusCode;
ResponseModel = model;
}
public T ResponseModel { get; private set; }
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
var response = httpRequestMessage.CreateResponse(statusCode, ResponseModel);
return Task.FromResult(response);
}
}
That gives you an easily testable class in HttpStatusCodeResultWithContent, that allows you to return any content with any HTTP Status Code.
Then from your controller code,
var pagedListResult = someObject.GetPagedList();
return new HttpStatusCodeResultWithContent<PagedListResult<T>(Request, HttpStatusCode.OK, pagedListResult);
You can then use extension methods if you like on ApiController to wrap up access to this - that's pretty much all that's going on inside ApiController, e.g. here's what the 'Ok' method on ApiController looks like.
protected internal virtual OkNegotiatedContentResult<T> Ok<T>(T content)
{
return new OkNegotiatedContentResult<T>(content, this);
}
In our web app, using Spring MVC 3.2 we display many paginated lists of different objects, and the links to other pages in the list are constructed like this:
/servlet/path?pageNum=4&resultsPerPage=10&sortOrder=ASC&sortBy=name
although there might be additional request parameters in the URL as well (e.g., search filters).
So we have controller methods like this:
#RequestMapping(method = RequestMethod.GET, value="/ajax/admin/list")
public String ajaxlistGroups(Model model,
#RequestParam(value="pageNumber",required=false,defaultValue="0") Long pageNumber,
#RequestParam(value="resultsPerPage",required=false,defaultValue="10") int resultsPerPage,
#RequestParam(value="sortOrder",required=false,defaultValue="DESC") String sortOrder,
#RequestParam(value="orderBy",required=false,defaultValue="modificationDate")String orderBy) {
// create a PaginationCriteria object to hold this information for passing to Service layer
// do Database search
// return a JSP view name
}
so we end up with this clumsy method signature, repeated several times in the app, and each method needs to create a PaginationCriteria object to hold the pagination information, and validate the input.
Is there a way to create our PaginationCriteria object automatically, if these request params are present? E.g., replace the above with:
#RequestMapping(method = RequestMethod.GET, value="/ajax/admin/list")
public String ajaxlistGroups(Model model, #SomeAnnotation? PaginationCriteria criteria,
) {
...
}
I.e., is there a way in Spring to take a defined subset of requestParams from a regular GET request, and convert them to an object automatically, so it's available for use in the Controller handler method? I've only used #ModelAttribute before, and that doesn't seem the right thing here.
Thanks!
Spring 3.2 should automatically map request parameters to a custom java bean.
#RequestMapping(method = RequestMethod.GET, value="/ajax/admin/list")
public String ajaxlistGroups(Model model, PaginationCriteriaBean criteriaBean,
) {
//if PaginationCriteriaBean should be populated as long as the field name is same as
//request parameter names.
}
I'm not sure how Spring magically achieve this(without #ModelAttribute), but the code above works for me.
There is another way to achieve the same goal, you can actually achieve more, that is spring AOP.
<bean id="aspectBean" class="au.net.test.aspect.MyAspect"></bean>
<aop:config>
<aop:aspect id="myAspect" ref="aspectBean">
<aop:pointcut id="myPointcut"
expression="execution(* au.net.test.web.*.*(..)) and args(request,bean,..)" />
<aop:before pointcut-ref="myPointcut" method="monitor" />
</aop:aspect>
</aop:config>
in application context, we declare Aspect bean as well as Pointcut along with advice, which in your case is before advice
the following is source code
public class PaginationCriteriaBean {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
//custom Aspect
public class MyAspect {
public void monitor( HttpServletRequest request,PaginationCriteriaBean bean){
//populate your pagination bean
bean.setId(request.getParameter("id"));
bean.setName("my new name");
}
}
#RequestMapping(value="/app")
public String appRoot(HttpServletRequest request,PaginationCriteriaBean bean){
System.out.println(bean.getId());
System.out.println(bean.getName());
return "app";
}
by doing so, the aspect will intercept spring controller and populate PaginationCriteriaBean based on request parameters, and you can even change the original value in request. With this AOP implementation you are empowered to apply more logic against Pagination, such as logging and validation and etc.
I am trying to create a custom attribute in mvc to use it's parameters in a view as breadCrumb.
well, this is the code of the attribute
[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
public class BreadCrumbAttribute : Attribute {
public BreadCrumbAttribute(string title, string parent, string url) {
this._title = title;
this._parent = parent;
this._url = url;
}
#region named parameters properties
private string _title;
public string Title {
get { return _title; }
}
private string _url;
public string Url {
get { return _url; }
}
private string _parent;
public string Parent {
get { return _parent; }
}
#endregion
#region positional parameters properties
public string Comments { get; set; }
#endregion
}
this is the call of the attribute
[BreadCrumbAttribute("tile", "parent name", "url")]
public ActionResult Index() {
//code goes here
}
this is a way of how I'd like to get the values. (this is a partial view)
System.Reflection.MemberInfo inf = typeof(ProductsController);
object[] attributes;
attributes = inf.GetCustomAttributes(typeof(BreadCrumbAttribute), false);
foreach (Object attribute in attributes) {
var bca = (BreadCrumbAttribute)attribute;
Response.Write(string.Format("{0}><a href={1}>{2}</a>", bca.Parent, bca.Url, bca.Title));
}
Unfortunately, the attribute didn't get call with the way I implement it. Although, If I add the attribute in Class instead of an Action method it worked.
How could I make it work?
Thanks
The problem is that you are using reflection to get the attributes for the class, so naturally it does not include attributes defined on the action method.
To get those, you should define an ActionFilterAttribute, and in the OnActionExecuting or OnActionExecuted method, you can use filterContext.ActionDescriptor.GetCustomAttributes() method (MSDN description here).
Note that with this solution, you will likely have two different types of attributes: The first one is the one you wrote, to define the breadcrumbs. The second is the one that looks at the attributes on the executing action and builds up the breadcrumb (and presumably adds it to the ViewModel or sticks it in HttpContext.Items or something).
I have a simple class in asp.net mvc that looks like this:
public class JsonResponseItem
{
public string Key { get; set; }
public string Value { get; set; }
public JsonResponseItem(string key, string value)
{
Key = key;
Value = value;
}
}
In my controllers I create a list of that type
List<JsonResponseItem> response = new List<JsonResponseItem>();
so I can easily manage and add to the Json response. A dictionary object is kind of hard to do that with.
When I return the json object
return Json(response);
It deserializes it so I have to reference everything by index first, because of the list. So if I had a property called "IsValid" I would have to reference it like this "IsValid[0]". I have way too much javascript code to make these changes.
How could I deserialize the JsonResponseItem class so I don't need the index reference in there?
Thanks!
A Dictionary<string, string> would serialize into exactly the Json you're asking for. If you don't want to expose directly a dictionary, wrap it around in another class or use Json(response.ToDictionary(item => item.Key).