Handling more than 2 possible returned values? - coding-style

When a function returns a boolean you can easily
if (task()){
// it worked!
}else{
// it failed.
}
But when it returns multiple different values it gets messier
var status = task();
if (status == 1){
// hmm
}else if (status == 2){
// hmmmmm
}else if (status == 3){
// hmmmmmmmm!
}
..is there a neater way of handling it?
Edit: In response to the answers that recommend switch statements, yes I know about those. I was asking for something neater than even that?

I can't tell what language you are using (JavaScript?) but I generally write code like this:
var result = task();
switch (result)
{
case 1:
handleStatus1();
break;
case 2:
handleStatus2();
break;
default:
handleEverythingElse();
break;
}

Depends on a language's possibilities, but I'd do something like this in JavaScript:
var handle_task_1 = function () {
// handle task 1
};
var handle_task_2 = function () {
// handle task 2
};
var tasks = {
1: handle_task_1,
2: handle_task_2,
"default": function() {},
};
tasks[task()]();
// Or, with a default action. But it may be too much for some people :)
(tasks[task()] || tasks["default"])();

Most languages have a switch statement, something like:
switch (task()) {
case 1: // do stuff
break;
case 2: // other stuff
break;
/// etc.
default: // what?!
Error("Unhandleable status code");
}

If you have many chained if commands each executing a unique block of code, you might consider using a map of simple functor classes. Ideally, the application's startup would populate that map and you can just call the actions from an instance of that map
The code would look like this
Action action = (Action) contextMap.get(task());
action.do();
This has the advantage that adding new tasks requires only defining a new class for that task and adding it to the contextMap on startup.
There are some other nice things about this approach
taskA() and taskB() can share the same contextMap and even some of the same Actions so you have less code duplication
Actions can be unit tested more easily (usually)
Sharing of code between actions will be easy without ending up with spaghetti code or complex if(status > 2 && status !=7 ) statements
And of course, interfaces, varargs and other syntactic sugar helps here.

If you're talking about an integer or other primitive return type, the best approach I know is the switch statement.
switch (status)
{
case 1:
// hmm
break;
case 2:
// hmmm
break;
}
However, if you're returning an object that defines the behavior following the method call things become much neater.
Say you have an interface ISomething and two (or more) objects that implement that interface (ASomething and BSomething). If the method's return type is ISomething, the code becomes:
ISomething result = task();
result.DoSomething();

Maybe you are looking for exceptions?
Then you don't need to clutter your code for the successful case, and for the various error cases you can throw different exceptions as necessary.

Related

Cypress returning Synchronous value within Async command?

So I think this is probably me mixing up sync/async code (Mainly because Cypress has told me so) but I have a function within a page object within Cypress that is searching for customer data. I need to use this data later on in my test case to confirm the values.
Here is my function:
searchCustomer(searchText: string) {
this.customerInput.type(searchText)
this.searchButton.click()
cy.wait('#{AliasedCustomerRequest}').then(intercept => {
const data = intercept.response.body.data
console.log('Response Data: \n')
console.log(data)
if (data.length > 0) {
{Click some drop downdowns }
return data < ----I think here is the problem
} else {
{Do other stuff }
}
})
}
and in my test case itself:
let customerData = searchAndSelectCustomerIfExist('Joe Schmoe')
//Do some stuff with customerData (Probably fill in some form fields and confirm values)
So You can see what I am trying to do, if we search and find a customer I need to store that data for my test case (so I can then run some cy.validate commands and check if the values exist/etc....)
Cypress basically told me I was wrong via the error message:
cy.then() failed because you are mixing up async and sync code.
In your callback function you invoked 1 or more cy commands but then
returned a synchronous value.
Cypress commands are asynchronous and it doesn't make sense to queue
cy commands and yet return a synchronous value.
You likely forgot to properly chain the cy commands using another
cy.then().
So obviously I am mixing up async/sync code. But since the return was within the .then() I was thinking this would work. But I assume in my test case that doesn't work since the commands run synchronously I assume?
Since you have Cypress commands inside the function, you need to return the chain and use .then() on the returned value.
Also you need to return something from the else branch that's not going to break the code that uses the method, e.g an empty array.
searchCustomer(searchText: string): Chainable<any[]> {
this.customerInput.type(searchText)
this.searchButton.click()
return cy.wait('#{AliasedCustomerRequest}').then(intercept => {
const data = intercept.response.body.data
console.log('Response Data: \n')
console.log(data)
if (data.length) {
{Click some drop downdowns }
return data
} else {
{Do other stuff }
return []
}
})
}
// using
searchCustomer('my-customer').then((data: any[]) => {
if (data.length) {
}
})
Finally "Click some drop downdowns" is asynchronous code, and you may get headaches calling that inside the search.
It would be better to do those actions after the result is passed back. That also makes your code cleaner (easier to understand) since searchCustomer() does only that, has no side effects.
you just need to add return before the cy.wait
here's a bare-bones example
it("test", () => {
function searchCustomer() {
return cy.wait(100).then(intercept => {
const data = {text: "my data"}
return data
})
}
const myCustomer = searchCustomer()
myCustomer.should("have.key", "text")
myCustomer.its("text").should("eq", "my data")
});

Go to next page until element found

I'm using Cypress for my automated tests. I'm trying to find a product on a page and click on it. If the product not displayed on the page, go to the next one until it is found.
I've been trying a lot of things already: while loop, each loop, simple cy.get but none of them work. Can anyone help me to solve this?
You'll need a recursive command, implementation of which will depend on your specific scenario. There's no one-size-fits-all solution, but generally it will look something like this:
function findElem ( targetSelector ) {
// first, we need to query a container (could be table, or a generic item
// container). The important thing is, this container must exist on every
// page you'll traverse.
cy.get('.someContainer').then( $container => {
// synchronously find the target element, however you want. In this
// example I use an attribute selector, but you can do whatever you
// want.
if ( $container.find(targetSelector).length ) {
return true;
} else {
return false;
}
}).then( found => {
if ( found ) {
return cy.log(`found elem "${targetSelector}"`);
} else {
// synchronously check if there's a next page/table
if ( Cypress.$('.nextPageButton').length ) {
// when know that there is a next page, click it using cypress
cy.get('.nextPageButton').click();
// here, assert that next page/table is loaded, possibly by
// asserting that current page/table is removed from DOM
// then, recurse
return findElem(targetSelector);
} else {
throw new Error(`Couldn't find elem "${targetSelector}" on any page`);
}
}
});
}
it('test', () => {
findElem(`[data-id="42"]`);
});
The crux of the solution is using a combination of commands to query a container, and synchronous inspection (using jQuery or whatever) to find the actual element. Learn more at Conditional Testing.
For a concrete implementation, you can refer to an older answer I gave to a similar question.

Single Responsibility Principle, Test Driven Development, and Functional Design

I am fairly new to Test Driven Development and I just started learning the SOLID principles so I was hoping someone could help me out. I'm having some conceptual trouble understanding the Single Responsibility Principle in the context of developing unit tests and methods in the TDD paradigm. For instance, say I want to develop a method that deletes an item from a database- before my code would have looked like the following...
I'd start with defining a test case:
"Delete_Item_ReturnsTrue": function() {
//Setup
var ItemToDelete = "NameOfSomeItem";
//Action
var BooleanResult = Delete( ItemToDelete );
//Assert
if ( BooleanResult === true ) {
return true;
} else {
console.log("Test: Delete_Item_ReturnsTrue() - Failed.");
return false;
}
}
I'd run the test to make sure it failed, then I'd develop the method...
function Delete( ItemToDelete ) {
var Database = ConnectToDatabase();
var Query = BuildQuery( ItemToDelete );
var QueryResult = Database.Query( Query );
if ( QueryResult.error !== true ) {
//if there's no error then...
return true;
} else {
return false;
}
}
If I'm understanding the Single Responsibility Principle correctly, the method that I originally wrote had the responsibilities of deleting the item AND returning true if there wasn't an error. So if I follow the SOLID paradigm the original method should be refactored to look something like...
function Delete( WhatToDelete, WhereToDeleteItFrom ) {
WhereToDeleteItFrom.delete( WhatToDelete );
}
Doing the design as such, changed my method from a boolean function to a void function so now I can't really test the new method in the same manner I was testing my old method.
I guess I could test for thrown exceptions but then doesn't that make it an integration test rather than a unit test because there's no actual exception thrown in the method?
Do I design and implement an extra function which checks the database for use in my unit test?
Do I just not test it because it's void? How exactly does that work in TDD?
Do I pass in a mock repository and then return it after it's state has changed? Doesn't that just essientially bring me back to square one?
Do I pass in a reference to a mock repository and then just test against the repository after the method completes? Wouldn't that be considered a side effect though?
So the single responsibility principle says: They should be exact one reason when I need to change a function.
So let's look at your function:
function Delete( ItemToDelete ) {
var Database = ConnectToDatabase();
var Query = BuildQuery( ItemToDelete );
var QueryResult = Database.Query( Query );
if ( QueryResult.error !== true ) {
//if there's no error then...
return true;
} else {
return false;
}
}
Database changes: ConnectToDatabese() needs a change, but not this function
Changes in the db structure: BuildQuery() needs to be changed (maybe)
...
So on the first look, your function looks good. The naming on some places is a little bit confusing. A function should be start with a small letter. For example "connectToDatabase()". It is a little bit surprising that connectToDatabase returns an Object.
The name BuildQuery seems to be wrong, because BuildQuery( myItem ) returns a query wich is deleting something.
But I would never have such a long complicated function which just one testcase.
You need to write more test cases.
For the first test case you could write the function like that:
function Delete( ItemToDelete) {
return true
}
The next testcase could be "call the buildDeleteQuery function with the item id". At that point you need to think about how you call your db. If you have a dbObject, which does that you could mock that Object.
function Delete( ItemToDelete ) {
buildDeleteQuery( ItemToDelete.id )
return true
}
Now more and more test cases. Remember that there will be also test cases for buildDeleteQuery. But for the outer function you could mock buildDeleteQuery.
Now to answer some of your questions:
When you first write the test and then write the code, you will have testable code.
That code looks different, because the tests should be not to complicated. When you want easy tests you will automaticly have more smaller functions.
Yes, you will write a test for every function you call.
Maybe you will mock objects. And if you are not able to test your db call without a wrapping function you will create a function, which allows you to test that functionality.
Remember your tests are the documentation of your code. So keep them simple as possible.
But the most important thing: Keep practicing! When you start with TDD it takes some time. A good and fun resource is: Uncle Bobs Bowling Kata Just download the slides from the website and look how tdd is done step by step.

Best practices for returning different conditional results in web api

Suppose I have web api application using ASP.NET. In one of the actions I'm checking if I can activate a free trial period for the given user. Now from one point of view, result of this action is either successful or unsuccessful. But in case of an unsuccessful result, I'd like to inform the client why the request has been denied and then the client can decide what to do.
There are multiple if-checks in this action and each one of them can deny the incoming request. Further more, we can have different successful result conditions as well.
What is the right way to return these different conditions so the client can easily distinguish between them?
What I'm doing right now is something like this:
public IHttpActionResult ActivateFreeTrial()
{
BaseResult result = new BaseResult(); // This class has a property called Status
if(!FirstCondition)
{
// Unsuccessful
result.Status = 90;
return Ok(result)
}
if(!SecondCondition)
{
// Unsuccessful
result.Status = 91;
return Ok(result)
}
// Some more checks...
if(!SixthCondition)
{
// Successful
result.Status = 1;
return Ok(result);
}
else {
// Successful
result.Status = 2;
return Ok(result);
}
}
Client needs to know which condition generated the result so that's why I'm assigning a number to distinguish between the different conditions. So in client-side I can do something like:
CallActivateFreeTrial()
.then(function(res){
if (res.Status == 1)
{
// Successful result but with status 1
}
else if (res.Status == 2)
{
// Successful result but with status 2
}
else if (res.Status == 90)
{
// Unsuccessful result but with status 90
}
else if (res.Status == 91)
{
// Unsuccessful result but with status 91
}
}, function(error){
})
I hardly think what I'm doing right now is considered to be a good practice. Is there a better way to return different conditional results to the client?
I would like to know where you get !FirstCondition, !SecondCondition values to confirm my answer but I believe it's a bad practice. If you have a different result, then you'll change ActivateFreeTrial method. I believe a strategy or state pattern could help you. So instead of return "status code" to your client, you can return the name of a function that client should call.
Strategy pattern
http://www.dofactory.com/net/strategy-design-pattern
State pattern
http://www.dofactory.com/net/state-design-pattern

System.IObservable<string> to System.IObservable<System.Collections.Generic.List<string>>

How can I convert System.IObservable<string> to System.IObservable<System.Collections.Generic.List<string>>?
public static IObservable<List<string>> GetUrlList(Uri url) {
var result = (from request in Observable.Return(GetWebRequest(url, false))
from response in Observable.FromAsyncPattern<WebResponse>(
request.BeginGetResponse, request.EndGetResponse)()
from item in GetUrlCollection(response).ToObservable()
select item);
return result;
}
Here the type of the item is "list of string". I need to convert that to IObservable List of strings. How can I achieve this?
Try this:
public static IObservable<List<string>> GetUrlList(Uri url)
{
var result = (
from request in Observable.Return(
GetWebRequest(url, false))
from response in Observable.FromAsyncPattern<WebResponse>(
request.BeginGetResponse, request.EndGetResponse)()
from item in GetUrlCollection(response)
.ToObservable()
.ToArray()
select item
.ToList());
return result;
}
My only concern with this whole approach is that your GetUrlCollection(response) is returning an enumerable. You really should code this to return an observable.
Hmmm I think Observable.Start is your friend here. You have a bunch of code that it looks like you are forcing into Observable Sequences, when they really don't look like they are.
Remember Rx is designed to work with sequences of push data. You seem to have a sequence of 1 that happens to be a List. TPL/Task/async would be a good fit here.
If you do want to use Rx, I would suggest avoiding boucing around between IEnumable and IObservable. Doing so is a quick way to creating nasty race conditions and confusing the next developer.
public static IObservable<List<string>> GetUrlList(Uri url)
{
return Observable.Start(()=>
{
var request = GetWebRequest(url, false);
return GetUrlCollection(request);//Code change here??
});
}
Here you can happily be synchronous in your Observable.Start delegate. This should be a lot easier for the next guy to understand (i.e. this is a single value sequence with the UrlCollection as the value).

Resources