2015-07-14 25 views
7

Kod tabanımıza, hata izlemeden düzgün şekilde gizlenen bazı özel onaylar eklemek istiyorum. Birisinin statik olarak içe aktarılabileceği bir kamu statik yöntemini nasıl yazacağımı biliyorum. Eski iddiaları yeniden kullanmayı veya yeni bir AssertionError atmayı biliyorum.Hata İzlemesinde Gösterilmeyen özel JUnit4 iddiaları oluşturma

Nasıl yapılacağını anlayamadığım, yeni özel onaylamaların Hata İzlemesi dışında kalmasıdır. Başarısızlık iddiasının ilk isabeti, onaylama kodunun kendisinin OLMADIĞINI, ancak iddiayı deneyen test kodunun kullanılmasında kullanılmıştır.

Yığın filtrelemeyi denetleyen bir filtertrace özniteliği olduğunu biliyorum, ancak yeni onaylamaları filtreye eklemek için ne yapmam gerektiğine dair iyi bir belge bulamıyorum.

Ben ne yapmak istediğinizi bir örneği: myAssertTrueFailing ait

package testassertions; 

import static newassertions.MyAssertions.myAssertTrue; 

import org.junit.Test; 

public class ExampleTest { 
    @Test 
    public void myAssertTruePassing() { myAssertTrue(true); } 

    @Test 
    public void myAssertTrueFailing() { myAssertTrue(false); } 
} 

package newassertions; 

import static org.junit.Assert.assertTrue; 

public class MyAssertions { 

    public static void myAssertTrue(boolean b) { 
     assertTrue(b); 
    } 
} 

Başarısızlık Trace() gösterir:

java.lang.AssertionError 
    at newassertions.MyAssertions.myAssertTrue(MyAssertions.java:8) 
    at testassertions.ExampleTest.myAssertTrueFailing(ExampleTest.java:12) 

Ben sadece gösteri yapmak için oraya:

java.lang.AssertionError 
    at testassertions.ExampleTest.myAssertTrueFailing(ExampleTest.java:12) 

cevap

2

another question about cleaning noise from stack traces'da belirtildiği gibi, IDE'nizden gelen sınıfları filtrelemek muhtemelen en kolay çözümdür. Aslında, sorunuzda gösterdiğiniz yığın izleri zaten filtrelenmiş. Eğer gerçekten kodda bunu yapmak istiyorsa

, aşağıda gibi özel sav sınıf şeye filtreleme ekleyebilirsiniz:

package newassertions; 

import static org.junit.Assert.assertTrue; 
import java.util.ArrayList; 

public class MyAssertions { 

    public static void myAssertTrue(boolean b) { 
     try { 
      assertTrue(b); 
     } catch (AssertionError e) { 
      filterStackTrace(e); 
      throw e; 
     } 
    } 

    private static void filterStackTrace(AssertionError error) { 
     StackTraceElement[] stackTrace = error.getStackTrace(); 
     if (null != stackTrace) { 
      ArrayList<StackTraceElement> filteredStackTrace = new ArrayList<StackTraceElement>(); 
      for (StackTraceElement e : stackTrace) { 
       if (!"newassertions.MyAssertions".equals(e.getClassName())) { 
        filteredStackTrace.add(e); 
       } 
      } 
      error.setStackTrace(filteredStackTrace.toArray(new StackTraceElement[0])); 
     } 
    } 
} 

kapsayan sınıfın adı 'newassertions.MyAssertions' (kodlanmış) bu örnekte yığın izinden filtrelenir. Bu mekanizma, aynı zamanda, sadece diğer iddialardan alınanları değil, kendiniz oluşturduğunuz bir AssertionError'dan gelen yığın izini filtrelemek için de çalışır.

+0

Bu, üstte bazı noktalı virgüllerin eksik ama çok umut verici görünüyor. – CandiedOrange

+0

Re. Yorumu düzenle: Bu şişman parmaklı gremlinler. Her neyse, bu iyi görünüyor. Gerçek yığın izini görmek için herhangi bir en saf gereksinimi içeren filtreyi devre dışı bırakacak, ancak bu kod çözümünü varsayılan olarak bırakacak bir yapılandırma kodu eklemeyi tercih ediyorum. Yani, konfigürasyonumuzu değiştirmeye yetkili olmadıkça, paketlerimizden birini filtreleyebilirim. Çevremizde test etmek için bunu işte kodlama şansına ihtiyacımız var. – CandiedOrange

1

Özel bir JUnit yöntem kuralı ile birlikte özel öneriler kullanabilirsiniz. Özel öneriler, AssertionError alt türüyle çalışabilir. Bu, Junit iddialarını ve özel ifadeleri birlikte kullanmanıza bile izin verir.

Örnek Burada

durumda bir onaylama failes MyAssertionError s atar özel bir MyAssert sınıfı kullanan bir örnektir. JUnit kuralı MyAssertionError'u işler ve hata izinin ayrıntılarını gizler. verememeniz iz kural TestVerifier bu özel kullanma

public class RuleTest { 

    @Rule 
    public TestVerifier testVerifier = new TestVerifier(); 

    @Test 
    public void myAssertOk() { MyAssert.assertCondition("ok", true); } 

    @Test 
    public void myAssertNotOk() { MyAssert.assertCondition("nok", false); } 

    @Test 
    public void junitAssertNotOk() { assertTrue(false); } 

    @Test 
    public void junitAssertOk() { assertTrue(true); } 

    static class TestVerifier implements TestRule { 

    @Override 
    public Statement apply(Statement base, Description description) { 
     return new Statement() { 

     @Override 
     public void evaluate() throws Throwable { 
      try { 
      base.evaluate(); 
      } catch (MyAssertionError t) { 
      throw new AssertionError("Test failed: " + description.getMethodName()); 
      } 
     } 
     }; 
    } 

    } 

    static class MyAssertionError extends AssertionError { 
    public MyAssertionError(Object detailMessage) { super(detailMessage); } 
    } 

    static final class MyAssert { 
    public static void assertCondition(String message, boolean condition) { 
     if (!condition) { throw new MyAssertionError(message); } 
    } 
    } 
} 

sadece diyecekler: IDE'nizde olarak

java.lang.AssertionError: Test failed: verifierTest 
    at RuleTest$TestVerifier.apply(RuleTest.java:26) 
    at org.junit.rules.RunRules.applyAll(RunRules.java:26) 
    ... 

bu gibi görünecektir:

IDE screen shot

+0

Bu örneği anlamıyorum. AssertTrue() hakkında özel bir şey yok. Bana göster benimAssertTrue(). – CandiedOrange

+0

@CandiedOrange Önceki cevabımı biraz değiştirdim.Önceki versiyonda, * özel onaylamalar gerektirdiğini özledim. –

+0

Bu biraz daha iyi, ancak başarısızlık izinde hala büyük bir sorun var. Çalıştırdığımda, "public class RuleTest {", 10. satırdaydı. JunitNotOK testini incelediğimde (tıklayın), assertTrue() 'nin çağrıldığı 22 numaralı satırdaki problemi doğru şekilde rapor ediyor. Ancak, myAssertNotOK() sınaması, 38 numaralı satırdaki sorunu bildirir. Bu, istisnanın atıldığı yerdeyken myAssertTrue() öğesinin aranmadığı durum değildir. Bilmem gerekiyordu ve başarısızlık izinin ilk satırı olduğunu söyleyen çizgiye ihtiyacım vardı. – CandiedOrange

4

Birlikte org.junit.Assert.assertThat kullanmayı düşündünüz mü Hamcrest eşleştiriciler?

Hamcrest ile, onaylama yöntemlerini değiştirmeniz gerekmez, bunun yerine kendi eşleştiricilerinizi uygulamalısınız.Örneğin, böyle bir eşleyici yazmak, BCrypt karma şifre açık şifresi ile eşleşen doğrulamak için:

public class MatchesPassword extends TypeSafeMatcher<String> { 

    private static final PasswordEncoder PASSWORD_ENCODER = new BCryptPasswordEncoder(); 

    private final String password; 

    public MatchesPassword(String password) { 
     this.password = password; 
    } 

    @Override 
    protected boolean matchesSafely(String encodedPassword) { 
     return PASSWORD_ENCODER.matches(password, encodedPassword); 
    } 

    @Override 
    public void describeTo(Description description) { 
     description.appendText("matches password "); 
     description.appendValue(password); 
    } 
} 

Sonraki yerde bir yöntem eklemek statik ithalat yapabilirsiniz:

Nihayet
public class CustomMatchers { 

    public static Matcher<String> matchesPassword(String password) { 
     return new MatchesPassword(password); 
    } 

} 

, yazma böyle test: bir uyumsuzluk böyle konsoluna kaydedilir

@Test 
public void passwordShouldMatch() { 
    PasswordEncoder passwordEncoder = new BCryptPasswordEncoder() 
    String plainPassword = "secret"; 
    String hashedPassword = passwordEncoder.encode(plainPassword); 

    assertThat(hashedPassword, matchesPassword(plainPassword)); 
} 

:

java.lang.AssertionError: 
Expected: matches password "wrong" 
    but: was "$2a$10$5lOyLzUeKMAYPJ5A3y5KfOi747DocksLPHgR7GG3XD8pjp8mhaf0m" 
    at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:18) 
    at org.junit.Assert.assertThat(Assert.java:956) 
    at org.junit.Assert.assertThat(Assert.java:923) 
    ... 

Not: BCryptPasswordEncoder, Spring Security'den alınmıştır ve sadece örnek olarak kullanılmıştır.

+0

Sert, eşleştiriciler, Hamcrest veya Spring'i kullanmayız. Java 5'teyiz. Evet biliyorum. Onunla uğraştığım şey. – CandiedOrange

+0

JUnit'in hangi sürümünü kullanıyorsunuz? AFAIK, JUnit, 4.4'de (2007'den itibaren) “assertThat” i ekledi ve Hamcrest'in temel eşleştirmelerini de ekledi (böylece ek bir kütüphaneye ihtiyacınız olmayacak). Bahar sadece bir örnek olarak kullanıldı, buna ihtiyacınız olmayacak. – hzpz

+0

Kullanabileceğiniz JUnit sürümüne ve 'assertThat' komutunu kullanabiliyor muydunuz? – hzpz

2

Yolculuğumdaki çözüm, zaten önerildiği gibi bir IDE filtresi de olacaktır. Eğer "kodlanmış" bir çözüm yaparsanız, bu otomatik bir oluşturma işleminde daha az izlenebilir olacaktır.

Eclipse'de tercihleri ​​açabilir ve Java -> JUnit'i seçebilir ve sağdaki düğmeleri kullanarak sınıf veya paket ekleyebilirsiniz.

Ama sadece eğlence için

:

gar çözümü oldukça makul sesler @ gerçekten programlı yapmak istiyorsanız

. Ancak, daha büyük miktarda iddianız varsa bu biraz sıkıcı olabilir.

Yapabilecekleriniz de AssertionError alt sınıfını oluşturmak ve stacktrace öğesinin kök dizinine filtre uygulamaktır. Burada

public class MyAssertionError extends AssertionError { 

    public MyAssertionError(String message) { 
     super(message); 
    } 

    @Override 
    public synchronized Throwable fillInStackTrace() { 
     super.fillInStackTrace(); 
     filterStackTrace(); 
     return this; 
    } 

    protected void filterStackTrace() { 
     StackTraceElement[] trace = getStackTrace(); 
     ArrayList<StackTraceElement> list = new ArrayList<StackTraceElement>(trace.length); 
     for (StackTraceElement element : trace) { 
      if (!element.getClassName().equals("newassertions.MyAssertions")) { 
       list.add(element); 
      } 
     } 
     this.setStackTrace(list.toArray(new StackTraceElement[0])); 
    } 

} 

Not iki şey: 1) ince ayrı pakette tüm iddialarını koyarsanız sağ tarafında 2) üzerinde sabit yazmak bu kadar boş olamaz bir StackTraceElement sınıf adı Ayrıca element.getClassName().startsWith("newassertions")

sizin iddia sınıfı sonra şuna benzer yazabilirsiniz:

package newassertions; 

public class MyAssertions { 

    public static void myAssertTrue(boolean b) { 
     if (!b) { 
      fail(null); 
     } 
    } 

    public static void fail(String message) { 
     if (message == null) { 
      throw new MyAssertionError(message); 
     } 
     throw new MyAssertionError(message); 
    } 


} 

Eğer Assert gelen yöntemleri çağırmak ama olamazdı Bu şekilde mo yazarsanız Karmaşık iddialar zaten bunu yapmak için birkaç neden var. Bununla birlikte, onaylama kodunuzu her şeyi büyük try-catch bloklarına sarmakla karşılaştırıldığında biraz daha temiz tutar.