Writing a mock web service

Many times when developing a mobile application, you may need to begin the development of your application before the real backend web service is available. To prevent the development from halting entirely, a good approach would be to develop a mock version of the service. This is also helpful when you need to write unit tests, or you must wait to add a real backend to your app later.

First, let's break down the operations our app will perform against a web server. The operations are as follows:

  1. Log in with a username and password.
  2. Register a new account.
  3. Get the user's list of friends.
  4. Add friends by their usernames.
  5. Get a list of the existing conversations for the user.
  6. Get a list of messages in a conversation.
  7. Send a message.

Now let's define an interface that offers a method for each scenario. The interface is as follows:

public interface IWebService
{
  Task<User> Login(string username, string password);

  Task<User> Register(User user);

  Task<User[]> GetFriends(int userId);

  Task<User> AddFriend(int userId, string username);

  Task<Conversation[]> GetConversations(int userId);

  Task<Message[]> GetMessages(int conversationId);

  Task<Message> SendMessage(Message message);
}

As you see, we're using asynchronous communication with the TPL (Task Parallel Library) technology.

Since communicating with a web service can be a lengthy process, it is always a good idea to use the Task<T> class for these operations. Otherwise, you could inadvertently run a lengthy task on the user interface thread, which would prevent user inputs during the operation. Task is definitely needed for web requests, since users could easily be using a cellular Internet connection on iOS and Android, and it will give us the ability to use the async and await keywords down the road.

Now let's implement a fake service that implements this interface. Place classes such as FakeWebService in the Fakes folder of the project. Let's start with the class declaration and the first method of the interface:

public class FakeWebService
{
  public int SleepDuration { get; set; }

  public FakeWebService()
  {
    SleepDuration = 1;
  }

  private Task Sleep()
  {
    return Task.Delay(SleepDuration);
  }

  public async Task<User> Login(string username, string password)
  {
    await Sleep();

    return new User { Id = 1, Username = username };
  }
}

We started off with a SleepDuration property to store a number in milliseconds. This is used to simulate an interaction with a web server, which can take some time. It is also useful for changing the SleepDuration value in different situations. For example, you might want to set this to a small number when writing unit tests so that the tests execute quickly.

Next, we implemented a simple Sleep method to return a task that introduce delays of a number of milliseconds. This method will be used throughout the fake service to cause a delay on each operation.

Finally, the Login method merely used an await call on the Sleep method and returned a new User object with the appropriate Username. For now, any username or password combination will work; however, you may wish to write some code here to check specific credentials.

Now, let's implement a few more methods to continue our FakeWebService class as follows:

public async Task<User> Register(User user)
{
  await Sleep();

  return user;
}

public async Task<User[]> GetFriends(int userId)
{
  await Sleep();

  return new[]
  {
    new User { Id = 2, Username = "bobama" },
    new User { Id = 2, Username = "bobloblaw" },
    new User { Id = 3, Username = "gmichael" },
  };
}

public async Task<User> AddFriend(int userId, string username)
{
  await Sleep();

  return new User { Id = 4, Username = username };
}

For each of these methods, we kept in mind exactly same pattern as the Login method. Each method will delay and return some sample data. Feel free to mix the data with your own values.

Now, let's implement the GetConversations method required by the interface as follows:

public async Task<Conversation[]> GetConversations(int userId)
{
  await Sleep();

  return new[]
  {
    new Conversation { Id = 1, UserId = 2 },
    new Conversation { Id = 1, UserId = 3 },
    new Conversation { Id = 1, UserId = 4 },	
  };
}

Basically, we just create a new array of the Conversation objects with arbitrary IDs. We also make sure to match up the UserId values with the IDs we've used on the User objects so far.

Next, let's implement GetMessages to retrieve a list of messages as follows:

public async Task<Message[]> GetMessages(int conversationId)
{
  await Sleep();

  return new[]
  {
    new Message
    {
      Id = 1,
      ConversationId = conversationId,
      UserId = 2,
      Text = "Hey",
    },
    new Message
    {
      Id = 2,
      ConversationId = conversationId,
      UserId = 1,
      Text = "What's Up?",
    },
    new Message
    {
      Id = 3,
      ConversationId = conversationId,
      UserId = 2,
      Text = "Have you seen that new movie?",
    },
    new Message
    {
      Id = 4,
      ConversationId = conversationId,
      UserId = 1,
      Text = "It's great!",
    },
  };
}

Once again, we are adding some arbitrary data here, and mainly making sure that UserId and ConversationId match our existing data so far.

And finally, we will write one more method to send a message as follows:

public async Task<Message> SendMessage(Message message)
{
  await Sleep();

  return message;
}

Most of these methods are very straightforward. Note that the service doesn't have to work perfectly; it should merely complete each operation successfully with a delay. Each method should also return test data of some kind to be displayed in the UI. This will give us the ability to implement our iOS and Android applications while filling in the web service later.

Next, we need to implement a simple interface for persisting application settings. Let's define an interface named ISettings as follows:

public interface ISettings
{
  User User { get; set; }

  void Save();
}

Note that you might want to set up the Save method to be asynchronous and return Task if you plan on storing settings in the cloud. We don't really need this with our application since we will only be saving our settings locally.

Later on, we'll implement this interface on each platform using Android and iOS APIs. For now, let's just implement a fake version that will be used later when we write unit tests. The interface is created by the following lines of code:

public class FakeSettings : ISettings
{
  public User User { get; set; }

  public void Save() { }
}

Note that the fake version doesn't actually need to do anything; we just need to provide a class that will implement the interface and not throw any unexpected errors.

This completes the Model layer of the application. Here is a final class diagram of what we have implemented so far:

Writing a mock web service
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.52.86