WCF Webプログラミングモデルの学習テスト Part2
次はDataContractを使用してオブジェクトの POST / GET / PUT / DELETE を行うサービスの学習テスト。長いよ(w
using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Runtime.Serialization; using System.ServiceModel; using System.ServiceModel.Web; using System.Text; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace LearningWCFTests { [TestClass] public class DataContractTest { ... [ServiceContract] public interface ICustomers { [OperationContract] [WebGet(UriTemplate = "customers")] List<Customer> GetCustomers(); [OperationContract] [WebGet(UriTemplate = "customers/{id}")] Customer GetCustomer(string id); [OperationContract] [WebInvoke(Method = "POST", UriTemplate = "customers")] Customer AddCustomer(Customer customer); [OperationContract] [WebInvoke(Method = "PUT", UriTemplate = "customers/{id}")] Customer UpdateCustomer(string id, Customer customer); [OperationContract] [WebInvoke(Method = "DELETE", UriTemplate = "customers/{id}")] void DeleteCustomer(string id); } [DataContract] public class Customer { [DataMember] public string Id { get; set; } [DataMember] public string Name { get; set; } [DataMember] public string Address { get; set; } [DataMember] public Uri Uri { get; set; } public override string ToString() { return String.Format("{0}, {1}, {2}, {3}", Id, Name, Address, Uri); } } [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] public class Customers : ICustomers { private int lastId_ = 0; private Dictionary<string, Customer> customers_ = new Dictionary<string, Customer>(); private static object syncRoot_ = new Object(); public List<Customer> GetCustomers() { List<Customer> customerList = new List<Customer>(); lock (syncRoot_) { foreach (Customer customer in this.customers_.Values) { customerList.Add(customer); } } return customerList; } public Customer GetCustomer(string id) { if (!customers_.ContainsKey(id)) { // HTTP ステータス 404 WebOperationContext.Current.OutgoingResponse.SetStatusAsNotFound(); return null; } Customer customer = customers_[id]; return customer; } public Customer AddCustomer(Customer customer) { lock (syncRoot_) { lastId_++; customer.Id = lastId_.ToString(); UriTemplateMatch match = WebOperationContext.Current.IncomingRequest.UriTemplateMatch; UriTemplate template = new UriTemplate("customers/{id}"); customer.Uri = template.BindByPosition(match.BaseUri, customer.Id); customers_.Add(customer.Id, customer); // HTTP ステータス 201 WebOperationContext.Current.OutgoingResponse.SetStatusAsCreated(customer.Uri); } return customer; } public Customer UpdateCustomer(string id, Customer customer) { if (!customers_.ContainsKey(id)) { // HTTP ステータス 404 WebOperationContext.Current.OutgoingResponse.SetStatusAsNotFound(); return null; } lock (syncRoot_) { customers_[id] = customer; } return customer; } public void DeleteCustomer(string id) { if (!customers_.ContainsKey(id)) { // HTTP ステータス 404 WebOperationContext.Current.OutgoingResponse.SetStatusAsNotFound(); return; } lock (syncRoot_) { customers_.Remove(id); } } } private static readonly Uri HostingBaseUri = new Uri("http://localhost:8000"); private static readonly Uri ClientBaseUri = new Uri("http://localhost:8000"); private WebServiceHost host_; private string aliceId_; private string bobId_; [TestInitialize] public void サービスホスティングの開始とCustomerの登録() { host_ = new WebServiceHost(typeof(Customers), HostingBaseUri); host_.Open(); using (WebChannelFactory<ICustomers> cf = new WebChannelFactory<ICustomers>(ClientBaseUri)) { ICustomers channel = cf.CreateChannel(); aliceId_ = channel.AddCustomer(new Customer() { Name = "Alice", Address = "123 Pike Place" }).Id; bobId_ = channel.AddCustomer(new Customer() { Name = "Bob", Address = "12323 Lake Shore Drive" }).Id; } } [TestCleanup] public void サービスホスティングの終了() { if (host_.State != CommunicationState.Closed) host_.Close(); } [TestMethod] public void Customerが追加できるべき() { using (WebChannelFactory<ICustomers> cf = new WebChannelFactory<ICustomers>(ClientBaseUri)) { ICustomers channel = cf.CreateChannel(); Customer john = channel.AddCustomer(new Customer() { Name = "John", Address = "4545 Wacker Drive" }); string expectedJohn = String.Format("{0}, John, 4545 Wacker Drive, http://localhost:8000/customers/{0}", int.Parse(bobId_) + 1); Assert.AreEqual<string>(expectedJohn, john.ToString()); } } [TestMethod] public void 生HTTPのPOSTでCustomerの追加ができるべき() { UriTemplate template = new UriTemplate("customers"); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(template.BindByPosition(ClientBaseUri)); request.Method = "POST"; request.ContentType = "application/xml; charset=utf-8"; string requestBody = "<DataContractTest.Customer xmlns=\"http://schemas.datacontract.org/2004/07/LearningWCFTests\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">" + "<Address>4545 Wacker Drive</Address>" + "<Id i:nil=\"true\"/>" + "<Name>John</Name>" + "<Uri i:nil=\"true\"/>" + "</DataContractTest.Customer>"; byte[] bytes = Encoding.UTF8.GetBytes(requestBody); request.ContentLength = bytes.Length; using (Stream requestStream = request.GetRequestStream()) { requestStream.Write(bytes, 0, bytes.Length); } HttpWebResponse response = (HttpWebResponse)request.GetResponse(); Assert.AreEqual<HttpStatusCode>(HttpStatusCode.Created, response.StatusCode); string responseBody = string.Format( "<DataContractTest.Customer xmlns=\"http://schemas.datacontract.org/2004/07/LearningWCFTests\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">" + "<Address>4545 Wacker Drive</Address>" + "<Id>{0}</Id>" + "<Name>John</Name>" + "<Uri>http://localhost:8000/customers/{0}</Uri>" + "</DataContractTest.Customer>", int.Parse(bobId_) + 1); using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8)) { Assert.AreEqual<string>(responseBody, reader.ReadToEnd()); } } [TestMethod] public void Customerの一覧が取得できるべき() { using (WebChannelFactory<ICustomers> cf = new WebChannelFactory<ICustomers>(ClientBaseUri)) { ICustomers channel = cf.CreateChannel(); List<Customer> culstomerList = channel.GetCustomers(); Assert.AreEqual<int>(2, culstomerList.Count); } } [TestMethod] public void 生HTTPのGETでCustomerの一覧が取得できるべき() { UriTemplate template = new UriTemplate("customers"); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(template.BindByPosition(ClientBaseUri)); request.Method = "GET"; request.ContentType = "application/xml; charset=utf-8"; HttpWebResponse response = (HttpWebResponse)request.GetResponse(); Assert.AreEqual<HttpStatusCode>(HttpStatusCode.OK, response.StatusCode); string responseBody = string.Format( "<ArrayOfDataContractTest.Customer xmlns=\"http://schemas.datacontract.org/2004/07/LearningWCFTests\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">" + "<DataContractTest.Customer>" + "<Address>123 Pike Place</Address>" + "<Id>{0}</Id>" + "<Name>Alice</Name>" + "<Uri>http://localhost:8000/customers/{0}</Uri>" + "</DataContractTest.Customer>" + "<DataContractTest.Customer>" + "<Address>12323 Lake Shore Drive</Address>" + "<Id>{1}</Id>" + "<Name>Bob</Name>" + "<Uri>http://localhost:8000/customers/{1}</Uri>" + "</DataContractTest.Customer>" + "</ArrayOfDataContractTest.Customer>", aliceId_, bobId_); using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8)) { Assert.AreEqual<string>(responseBody, reader.ReadToEnd()); } } [TestMethod] public void Customerが取得できるべき() { using (WebChannelFactory<ICustomers> cf = new WebChannelFactory<ICustomers>(ClientBaseUri)) { ICustomers channel = cf.CreateChannel(); Customer alice = channel.GetCustomer(aliceId_); string expectedAlice = String.Format("{0}, Alice, 123 Pike Place, http://localhost:8000/customers/{0}", aliceId_); Assert.AreEqual<string>(expectedAlice, alice.ToString()); Customer bob = channel.GetCustomer(bobId_); string expectedBob = String.Format("{0}, Bob, 12323 Lake Shore Drive, http://localhost:8000/customers/{0}", bobId_); Assert.AreEqual<string>(expectedBob, bob.ToString()); } } [TestMethod] public void 生HTTPのGETでCustomerが取得できるべき() { UriTemplate template = new UriTemplate("customers/{id}"); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(template.BindByPosition(ClientBaseUri, aliceId_)); request.Method = "GET"; request.ContentType = "application/xml; charset=utf-8"; HttpWebResponse response = (HttpWebResponse)request.GetResponse(); Assert.AreEqual<HttpStatusCode>(HttpStatusCode.OK, response.StatusCode); string responseBody = string.Format( "<DataContractTest.Customer xmlns=\"http://schemas.datacontract.org/2004/07/LearningWCFTests\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">" + "<Address>123 Pike Place</Address>" + "<Id>{0}</Id>" + "<Name>Alice</Name>" + "<Uri>http://localhost:8000/customers/{0}</Uri>" + "</DataContractTest.Customer>", aliceId_); using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8)) { Assert.AreEqual<string>(responseBody, reader.ReadToEnd()); } } [TestMethod] public void Customerが存在しない場合の取得はHTTPステータス404が返されるべき() { UriTemplate template = new UriTemplate("customers/{id}"); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(template.BindByPosition(ClientBaseUri, "9")); request.Method = "GET"; request.ContentType = "application/xml; charset=utf-8"; try { HttpWebResponse response = (HttpWebResponse)request.GetResponse(); Assert.Fail(); } catch (WebException ex) { Assert.AreEqual<WebExceptionStatus>(WebExceptionStatus.ProtocolError, ex.Status); Assert.AreEqual<HttpStatusCode>(HttpStatusCode.NotFound, ((HttpWebResponse)ex.Response).StatusCode); } } [TestMethod] public void Customerが更新できるべき() { using (WebChannelFactory<ICustomers> cf = new WebChannelFactory<ICustomers>(ClientBaseUri)) { ICustomers channel = cf.CreateChannel(); Customer alice = channel.GetCustomer(aliceId_); alice.Name = "Charlie"; Customer charlie = channel.UpdateCustomer(aliceId_, alice); Assert.AreEqual<string>("Charlie", charlie.Name); } } [TestMethod] public void 生HTTPのPUTでCustomerの更新ができるべき() { UriTemplate template = new UriTemplate("customers/{id}"); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(template.BindByPosition(ClientBaseUri, aliceId_)); request.Method = "PUT"; request.ContentType = "application/xml; charset=utf-8"; string requestBody = string.Format( "<DataContractTest.Customer xmlns=\"http://schemas.datacontract.org/2004/07/LearningWCFTests\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">" + "<Address>123 Pike Place</Address>" + "<Id>{0}</Id>" + "<Name>Charlie</Name>" + "<Uri>http://localhost:8000/customers/{0}</Uri>" + "</DataContractTest.Customer>", aliceId_); byte[] bytes = Encoding.UTF8.GetBytes(requestBody); request.ContentLength = bytes.Length; using (Stream requestStream = request.GetRequestStream()) { requestStream.Write(bytes, 0, bytes.Length); } HttpWebResponse response = (HttpWebResponse)request.GetResponse(); Assert.AreEqual<HttpStatusCode>(HttpStatusCode.OK, response.StatusCode); using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8)) { Assert.AreEqual<string>(requestBody, reader.ReadToEnd()); } } [TestMethod] public void Customerが存在しない場合の更新はHTTPステータス404が返されるべき() { UriTemplate template = new UriTemplate("customers/{id}"); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(template.BindByPosition(ClientBaseUri, "9")); request.Method = "PUT"; request.ContentType = "application/xml; charset=utf-8"; string requestBody = "<DataContractTest.Customer xmlns=\"http://schemas.datacontract.org/2004/07/LearningWCFTests\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">" + "<Address>NoWhere</Address>" + "<Id>9</Id>" + "<Name>Che</Name>" + "<Uri>http://localhost:8000/customers/9</Uri>" + "</DataContractTest.Customer>"; byte[] bytes = Encoding.UTF8.GetBytes(requestBody); request.ContentLength = bytes.Length; using (Stream requestStream = request.GetRequestStream()) { requestStream.Write(bytes, 0, bytes.Length); } try { HttpWebResponse response = (HttpWebResponse)request.GetResponse(); Assert.Fail(); } catch (WebException ex) { Assert.AreEqual<WebExceptionStatus>(WebExceptionStatus.ProtocolError, ex.Status); Assert.AreEqual<HttpStatusCode>(HttpStatusCode.NotFound, ((HttpWebResponse)ex.Response).StatusCode); } } [TestMethod] [ExpectedException(typeof(EndpointNotFoundException))] public void Customerが削除できるべき() { using (WebChannelFactory<ICustomers> cf = new WebChannelFactory<ICustomers>(ClientBaseUri)) { ICustomers channel = cf.CreateChannel(); channel.DeleteCustomer(aliceId_); channel.GetCustomer(aliceId_); } } [TestMethod] public void 生HTTPのDELETEでCustomerが削除できるべき() { UriTemplate template = new UriTemplate("customers/{id}"); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(template.BindByPosition(ClientBaseUri, aliceId_)); request.Method = "DELETE"; request.ContentType = "application/xml; charset=utf-8"; HttpWebResponse response = (HttpWebResponse)request.GetResponse(); Assert.AreEqual<HttpStatusCode>(HttpStatusCode.OK, response.StatusCode); using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8)) { Assert.AreEqual<string>(string.Empty, reader.ReadToEnd()); } } [TestMethod] public void Customerが存在しない場合の削除はHTTPステータス404が返されるべき() { UriTemplate template = new UriTemplate("customers/{id}"); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(template.BindByPosition(ClientBaseUri, "9")); request.Method = "DELETE"; request.ContentType = "application/xml; charset=utf-8"; try { HttpWebResponse response = (HttpWebResponse)request.GetResponse(); Assert.Fail(); } catch (WebException ex) { Assert.AreEqual<WebExceptionStatus>(WebExceptionStatus.ProtocolError, ex.Status); Assert.AreEqual<HttpStatusCode>(HttpStatusCode.NotFound, ((HttpWebResponse)ex.Response).StatusCode); } } } }