We need to be sure that our web application and mobile client are communicating correctly.
There is two-side communications from the server (Rails application with rspec testing) to the mobile client (Ruby application, has mspec testing framework) and from the mobile client to the server.
So to be sure that the synchronization mechanism is working as expected we need to test the following things:
Server prepares the data correctly.
Mobile client requests and gets
correct data.
Mobile client
prepares
the data to be sent to the server
correctly.
Server recieves and
parses the correct data from the
mobile client.
Servers sends
response to mobile client that
everything is ok.
Mobile client
should carry out appropriate actions
on the device.
How to test this in isolation?
As for all tests, don't plan for the unexpected. Start with what you know. The unexpected will rear it's ugly head soon enough to tell you what else you should test.
What you have is actually simple to test if you break it apart. Here is my approach:
public final static String SERVER_DATA = "Prepared data from the server";
#Test
public void testServerPreparesDataCorrectly() throws Exception {
... usual setup ...
String actual = server.handleRequest( CLIENT_REQUEST );
assertEquals( SERVER_DATA, actual );
}
public final static String CLIENT_REQUEST = "...";
#Test
public void testClientRequest() throws Exception {
... usual setup ...
String actual = client.getRequestData(...);
assertEquals( CLIENT_REQUEST, actual );
}
#Test
public void testClientResponseProcessing() throws Exception {
... usual setup ...
client.parseServerResponse( SERVER_DATA );
... verify client state ...
}
and so on. The basic idea is to put the input and output of each process step into a constant, then run the code which implements the process step for each expected input and validate the output. Where most outputs are also inputs for other tests.
If something changes, you update the inputs/outputs accordingly. Run the tests. And the failures will tell you which process steps you have to update.
Related
Having moved my mobile app development to Flutter I am now in the process of experimenting with using Dart as my main server side language. The productivity benefits in using a single coding language in both the app and on the server are considerable. To that end I have set up a server with an Nginx front end which proxies all dynamic web requests to an Angel/Dart server.
Angel is a remarkably well written package and I had a working server written up in no time at all. However, in order to have a fully functional backend I need to be able to use both Redis and PostgreSQL from within my server side Dart code. I am using the resp_client package to access Redis. The issue I have run into is with the fact that RespCommand.get is asynchronous. With my newbie knowledge of both Dart and Angel I am unable to find a way to acquire a Redis key value via RespCommand.get in an Angel route handler and then somehow use that value in the response it returns.
My entire Dart backend server code is shown below
import 'package:angel_framework/angel_framework.dart';
import 'package:angel_framework/http.dart';
import 'package:postgres/postgres.dart';
import 'package:resp_client/resp_client.dart';
import 'package:resp_client/resp_commands.dart';
class DartWeb
{
static Angel angel;
static AngelHttp http;
static RespCommands redis;
static PostgreSQLConnection db;
static init() async
{
angel = Angel();
http = AngelHttp(angel);
angel.get('/',rootRoute);
await prepareRedis();
await http.startServer('localhost',3000);
}
static prepareRedis() async
{
RespServerConnection rsc = await connectSocket('localhost');
RespClient client = RespClient(rsc);
redis = RespCommands(client);
}
static preparePostgres() async
{
db = new PostgreSQLConnection('serverurl',portNo,'database',username:'user',password:'password');
await db.open();
}
static void rootRoute(RequestContext req,ResponseContext res)
{
try
{
await redis.set('test','foobar',expire:Duration(seconds:10));
String testVal = await redis.get('test');
res.write('Done $testVal');
} catch(e) {res.write('++ $e ++');}
}
}
main() async {await DartWeb.init();}
If I start up this server and then access it through my web browser I end up with a 502 Bad Gateway message. Not surprising. dart2native main.dart -o mainCompiled returns the error await can only be used in async... message.
So I tried instead
try
{
res.write('Before');
redis.set('test','foobar',expire:Duration(seconds:10)).then((bool done)
{
res.write('DONE $done');
});
res.write('After');
} catch(e) {res.write('++ $e ++');}
which simply printed out BeforeAfter in my browser with the DONE bit never showing up although a quick test via redis-cli shows that the key test had in fact been created.
My knowledge of both Dart and Angel is still in its infancy so I guess I am doing something incorrectly here. Shorn of all the detail my questions are essentially these -
how do I call and get the result from async methods in an Angel route dispatcher?
given that I am editing my Dart code in VSCode on my local Windows machine which accesses the relevant dart files on my Ubuntu server I loose the benefits of error reporting provided by the VSCode Dart plugin. dart2native, as I have used here, helps out but it would be nicer if I could somehow get a running error report within VSCode as I do when building Flutter apps locally. How can I accomplish this - if at all possible?
It turns out that Dart/Angel does not impose excessively strict constraints on the signature of a route handler. So you can quite safely declare a route handler like this one
static Future<void> rootRoute(RequestContext req,ResponseContext res) async
{
try
{
res.write('!! Before ');
await redis.set('test','foobar',expire:Duration(seconds:10));
String test = await redis.get('test');
res.write('After $test !!');
} catch(e) {res.write('++ $e ++');}
}
With the route simply returning a Future we can now safely do anything we like there - including calling other asynchronous methods: in this instance to fetch a Redis key value.
I am attempting to create some UI tests using SpecsFor MVC, I am coming at this from a new user's point of view in terms of testing so could be easily missing something obvious.
The site I'm testing against already uses it's own test DB so I do not need to create one. when I build and debug normally on this site it also starts up a couple of WCF projects which we use for service layer interactions. Presumably I'll need to start these in the specs config but have not got that far yet.
I've followed the documentation and have created this method:
protected override void AfterConfigurationApplied()
{
var config = new SpecsForMvcConfig();
config.UseIISExpress()
.With(Project.Named("TestSite"))
.UsePort(55555)
.CleanupPublishedFiles()
.UseMSBuildExecutableAt(#"C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe");
config.BuildRoutesUsing(MvcApplication.RegisterRoutes);
config.UseBrowser(BrowserDriver.Chrome);
_host = new SpecsForIntegrationHost(config);
_host.Start();
}
The routing of the site is set in the Global.asax hence the setting in the above method.
I also have this very basic test in place to just see if I can get it working:
protected override void When()
{
SUT.NavigateTo<HomeController>(u => u.Index());
SUT.FindLinkTo<HomeController>(u => u.About())
.Click();
}
When I debug the tests it successfully starts Chrome but hangs for ages and eventually fails with this error:
OpenQA.Selenium.WebDriverException: The HTTP request to the remote WebDriver server for URL http://localhost:49924/session/bd15d6a15395b4ca204437c340639501/element timed out after 60 seconds.
I'm not sure where that port number or session etc are coming from.
If I'm running my web project normally (outside of this whole testing project) I see a URL like this:
https://localhost:55555
I would have thought I'd see something similar for these tests cases? It doesn't really matter in any case because they're not working.
Am I missing some element of the config? Do I need to set up the WCF layer to run as well?
Below I present a part of an Azure Web App that handles a device notification logic. What I'm doing is invoking the code shown below from a ASP MVC Controller.
But when I run it I get an hung (ever-pending) request from the browser.
I thought I've found a workaround by wrapping the SendAsync call in a BackgroundWorker thread. It's better, but I doesn't work right. For first couple of times (one or two) it works ok, but then it happens again, the wrapped thread hangs.
The code is not far different from the one on MSDN for a console application. What am I missing?
using System.Web.Configuration;
using Microsoft.Azure.Devices;
namespace MyTest
{
public class Sender
{
private readonly string connectionString;
private readonly Microsoft.Azure.Devices.ServiceClient serviceClient;
public Sender()
{
connectionString = WebConfigurationManager.AppSettings["ConnectionString"];
serviceClient = ServiceClient.CreateFromConnectionString(connectionString);
}
public async void SendRequest(string deviceId, string msgText)
{
var message = new Message();
message.Properties.Add("text", msgText));
await serviceClient.SendAsync(deviceId, message);
}
}
}
The problem was caused by inappropriate usage of ASP MVC framework.
It turned out that AsyncController has to be used instead of just Controller when a long running async\await is utilized. The pipeline must be async all the way.
I have to do a unit test for one method or function in MVC 2 .It will work on windows application ,But it shows the following Error Message in mvc2 can any one help me please
The Web request 'LocalHost' completed successfully without running the test. This can occur when configuring the Web application for testing fails (an ASP.NET server error occurs when processing the request), or when no ASP.NET page is executed (the URL may point to an HTML page, a Web service, or a directory listing). Running tests in ASP.NET requires the URL to resolve to an ASP.NET page and for the page to execute properly up to the Load event. The response from the request is stored in the file 'WebRequestResponse_HelloTest.html' with the test results; typically this file can be opened with a Web browser to view its contents.
here is my code Below
Home Controller:
public string Hello()
{
return "This is my First Unit Testing";
}
After that Right Click the controller , select the specified method and done a unit testing.
Here the testing Code below
HomeControllerTest.cs
[TestMethod()]
[HostType("ASP.NET")]
[AspNetDevelopmentServerHost("C:\\Users\\user\\Desktop\\praveen\\adcd\\adcd", "/")]
[UrlToTest("http://localhost:50332/")]
public void HelloTest()
{
HomeController target = new HomeController(); // TODO: Initialize to an appropriate value
string expected = "This IS my First Unit Testing"; // TODO: Initialize to an appropriate value
string actual;
actual = target.Hello();
Assert.AreEqual(expected, actual);
// Assert.Inconclusive("Verify the correctness of this test method.");
}
TestFiles:
WebRequestResponse_HelloTest.html
Finally I got a answer once i removed a [HostType("ASP.NET")] it will check my string and show the success message.Dont know how it works nu.Thanks for your effort to analyse my bug.
The controller is simply a class. You don't need to have the asp.net development server running in order to test your output. It depends on what you're trying to accomplish with your test but for me I'll write unit tests to verify my logic in the actions. If you want functional tests where your hitting your application and your having the test interact with your app via a browser driver and code as it exists on your local IIS or asp.net development server then my example won't help. If you want to just test your code/logic in the control then here's an example of a unit test to test the output of your controller.
[TestClass]
public class HomeControllerTests
{
[TestMethod]
public void Hello_ReturnsString()
{
// Arrange
const string expectedOutput = "This IS my First Unit Testing";
HomeController controller = new HomeController();
// Act
string actualResult = controller.Hello();
// Assert
Assert.AreEqual(expectedOutput, actualResult, "Expected the result to be 'This IS my First Unit Testing'");
}
}
Using the following tutorial: http://www.asp.net/web-api/overview/working-with-http/sending-html-form-data,-part-2, I used the following controller for the base of a file upload call I implemented:
public Task<HttpResponseMessage> PostFormData()
{
// Check if the request contains multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string root = HttpContext.Current.Server.MapPath("~/App_Data");
var provider = new MultipartFormDataStreamProvider(root);
// Read the form data and return an async task.
var task = Request.Content.ReadAsMultipartAsync(provider).
ContinueWith<HttpResponseMessage>(t =>
{
if (t.IsFaulted || t.IsCanceled)
{
Request.CreateErrorResponse(HttpStatusCode.InternalServerError, t.Exception);
}
// A whole lotta logic to save the file, process it, etc.
});
return task;
}
To save on space I didn't include the majority of the logic I wrote, since the error happens on the first line within of ContinueWith,
if (t.IsFaulted || t.IsCanceled)
If I run this locally from VS2010, both of the above booleans are false, and the code works perfectly - all of it, even extra few dozen lines I commented out. When I deploy it to a server running IIS7, t.IsFaulted is always true. I've never worked with asynchronous calls in C#, and have only done a few simple controllers in Web API...is there something I have to install/configure/etc. on a production server to make it work?
Making it more difficult is the fact that all of the exceptions that are occurring stay in that task (i.e. don't get caught by ELMAH), so I've no idea how to debug what's happening; IIS is also not logging any errors that are occurring in the event viewer...so I'm at a loss to know exactly what's going on. Any tips on how to make this debugging process easier?