2012년 12월 13일 목요일

[iOS] Volume Purchasing for Business Program


 어제, 미국에 한해 iOS 앱을 카피 단위로 판매할 수 있는 Volume Purchasing for Business Program(VPP)이 새로 발표됐다. 볼륨 앱 스토어를 통해 2~1000 Copy 단위(Volume)로 앱을 판매/구매할 수 있으며, 구매한 앱은 리딤 코드를 사용하여 앱스토어를 거치지 않고 자체적으로 배포가 가능하다. 아직은 미국 기업에 한정되어 있지만, 곧 한국에도 적용이 될 것이라 생각한다. 개인적인 차원에서도, 신규 사업분야 진출의 일환으로 모바일 사업을 준비 중인 팀 차원에서도 여러모로 큰 도움이 될 것 같다.

* 2013년 1월 현재, 미국 뿐 아니라 호주, 캐나다, 프랑스 등 10개 국가로 확대되었습니다.

[iOS] 루트 뷰 컨트롤러 표시하기

popToRootViewControllerAnimated: 메시지를 이용하면 루트 컨트롤러를 바로 표시할 수 있다.
[self.navigationController popToRootViewControllerAnimated:YES];


미리 알았다면 이런 짓은 안했을텐데.
for (int i = 0; i < [self.navigationController.viewControllers count]; i++) {
     [self.navigationController popViewControllerAnimated:NO];
}

[ASP.NET MVC] IValidatableObject 개체 테스트하기

IValidatableObject 인터페이스를 이용하여 유효성 검사를 수행하는 객체는 Validator 클래스를 통해 테스트할 수 있다. 다음은 테스트 주도 ASP.NET MVC 프로그래밍 책의 예제를 개선한 코드들이다. 참고로 책의 예제에서는 유효성 검사를 위해 커스텀 인터페이스를 사용하고 있다.

public class Todo : IValidatableObject
{
    //[Required]
    //[StringLength(25)]
    public string Title { get; set; }

    public IEnumerable<ValidationResult> Validate(
        ValidationContext validationContext)
    {
        if (string.IsNullOrEmpty(Title))
            yield return new ValidationResult(
                "제목이 입력되지 않았습니다.", 
                new[] { "Title" });

        if (Title != null && Title.Length > 25)
            yield return new ValidationResult(
                "제목이 25자를 초과할 수 없습니다.", 
                new[] { "Title" });
    }
}


제목 길이에 따른 각 개체들의 유효성 검사는 다음과 같이 테스트 한다.
[TestFixture]
public class TodoTest
{
    [Test]
    public void Title_Length_Should_Be_To_Maximum_Of_25_Characters()
    {
        // Arrange
        Todo longTodo = new Todo { Title = "123456789ABCDEF123456789ABCDEF" };
        Todo twentyFiveCharacterTodo = new Todo { Title = "123456789ABCDEF1234567" };
        Todo shortTodo = new Todo { Title = "123456789" };

        // Assert
        Assert.IsFalse(IsValid(longTodo));
        Assert.IsTrue(IsValid(twentyFiveCharacterTodo));
        Assert.IsTrue(IsValid(shortTodo));
    }

    private bool IsValid(IValidatableObject toValidate)
    {
        return Validator.TryValidateObject(
            toValidate, 
            new ValidationContext(toValidate, null, null), 
            null, 
            true);
    }
}


에러 메시지를 확인하고 싶다면 ValidationResult 리스트를 사용하면 된다.
[Test]
public void Title_Length_Should_Be_To_Maximum_Of_25_Characters()
{
    // Arrange
    Todo longTodo = new Todo { Title = "123456789ABCDEF123456789ABCDEF" };

    var result = new List<ValidationResult>();

    Validator.TryValidateObject(
        longTodo,
        new ValidationContext(longTodo, null, null),
        result,
        true);
        
    // Assert
    Assert.AreEqual(1, result.Count);
    Assert.AreEqual("제목은 25자를 초과할 수 없습니다.", result[0].ErrorMessage);
}

2012년 12월 12일 수요일

[ASP.NET MVC] ASP.NET MVC4 테스트 프로젝트에서 MVCContrib 사용 시 예외 발생 해결

ASP.NET MVC4  + MVCContrib 프레임워크를 사용하는 프로젝트들을 테스트하면 MVCContrib의 몇 몇 확장 메서드들이(ShouldMapTo<T>(), AssertActionRedirect<T>()와 같은) 이상한 예외들을 발생시킨다. 동일한 두 개의 타입을 틀린 타입으로 취급한다.

MvcContrib.TestHelper.ActionResultAssertionException : Expected result to be of type RedirectToRouteResult. It is actually of type RedirectToRouteResult.

MVCContrib3에서 참조되는 System.Web.Mvc.dll의 버전(1.0 ~ 3.0)이 테스트 프로젝트에서 참조된 버전(4.0)과 다르기 때문에 발생하는 문제다. App.config를 통해 1.0 ~ 3.0 버전을 강제로 4.0으로 바인딩하여 해결한다. 테스트 클래스 프로젝트에 App.config를 추가하고 다음과 같이 입력해준다.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <runtime>
        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
            <dependentAssembly>
                <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
                <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="4.0.0.0" />
            </dependentAssembly>
        </assemblyBinding>
    </runtime>    
</configuration>

2012년 11월 22일 목요일

[ASP.NET MVC] 인증 필터 적용 여부 테스트

컨트롤러에 적용된 특성(Attribute)들은 리플렉션을 이용해 테스트하면 된다.
Assert.IsTrue(typeof(HomeController)
    .GetCustomAttributes(false)
    .Any(o => o.GetType() == typeof(AuthorizeAttribute)));

2012년 11월 21일 수요일

[ASP.NET MVC] 몇 가지 테스트 케이스들.

ViewResult

액션 메서드의 실행 결과는 ViewResult 클래스를 통해 테스트한다.
[Test]
public void Should_Load_Index_View()
{
    var viewResult = new HomeController().Index() as ViewResult;

    // 뷰 이름 확인
    Assert.AreEqual("Index", viewResult.ViewName);
}


RedirectToRouteResult

POST 액션 메서드의 테스트는 모델 테스트를 포함한다. CRUD 작업 후 처리 방식에 따라 테스트 항목을 결정.
[Test]
public void Should_Delete_Item()
{
    var deleteItem = Items.FindBy("id");
    var redirectToRouteResult = 
        (RedirectToRouteResult)new SampleController().Delete(deleteItem);

    // Item이 제대로 삭제되었는지 확인
    Assert.IsFalse(Items.All.Contains(deleteItem));

    // 삭제 후 Index 뷰가 표시됐는지 확인
    Assert.AreEqual("Index", redirectToRouteResult.RouteValues["action"]);
}


FormCollection

모델 바인딩을 사용할 수 없는 POST 액션 메서드는 FormCollection 클래스를 이용해 테스트.
[Test]
public void Should_Create_Item()
{
    var item = new Item { Id = "1", Name = "Test Item" };

    var formValues = new FormCollection();
    formValues.Add("Id", item.Id);
    formValues.Add("Name", item.Name);

    var controller = new SampleController();
  
    var result = controller.Create(formValues) as RedirectToRouteResult;

    Assert.IsTrue(Items.All.Contains(item));
    Assert.AreEqual("Index", redirectToRouteResult.RouteValues["action"]);
}


.

2012년 11월 20일 화요일

[iOS] UIWebView에서 자바스크립트 실행하기

stringByEvaluatingJavaScriptFromString 메시지를 이용하면 웹페이지의 자바스크립트 코드를 실행하고 반환값을 받을 수 있다. (스크립트)실행 시간이 10초를 넘으면 자동으로 실행 취소가 되며 nil을 반환하니 주의할 것.
// getLayoutStyle 스크립트 메서드를 실행한다.
NSString* returnValue = 
    [self.webView stringByEvaluatingJavaScriptFromString:@"getLayoutStyle"];