JUnit4 fail () burada, ancak pass () nerede?


85

fail()JUnit4 kütüphanesinde bir yöntem var . Hoşuma gitti, ancak pass()kütüphanede olmayan bir yöntem eksikliği yaşıyorum . Neden böyle?

Bunun assertTrue(true)yerine kullanabileceğimi ama yine de mantıksız göründüğünü öğrendim.

@Test
 public void testSetterForeignWord(){
  try {
   card.setForeignWord("");
   fail();
  } catch (IncorrectArgumentForSetter ex){
  }

 // assertTrue(true);
 }

7
Sadece return ifadesini kullanın - çoğu durumda pass () olarak geçer.
topchef

@topchef o tek yorum kafaya vuruyor, diğer herkes hangisinin kabul edilebilir hangisinin kabul edilemez olduğunu tartışıyor.

Bazı test sistemleri (perl Test :: Simple) başarılı ve başarısız iddialar. Ancak Junit, başarılı ve başarısız olan test yöntemlerinin sayısını sayar . Bu nedenle Junit, bir passyöntem için aynı kullanıma sahip değildir .
Randall Whitman

Yanıtlar:


65

Test bir istisna oluşturmadığı sürece, @Testek açıklamanız beklenen bir istisna belirtmediği sürece geçer . Sanırım bir pass()JUnit'in testi kısa devre yapmak için her zaman geçme olarak yorumladığı özel bir istisna atabilir, ancak bu testlerin olağan tasarımına aykırı olur (yani başarıyı varsayın ve yalnızca bir iddia başarısız olursa başarısız olur) ve insanlar varsa Kullanılmasının tercih edilebilir olduğu fikri, pass()büyük bir test geçme grubunu önemli ölçüde yavaşlatacaktır (istisna yaratmanın ek yükü nedeniyle). Başarısız testler norm olmamalıdır, bu nedenle bu ek yüke sahip olmaları çok önemli değildir.

Örneğinizin şu şekilde yeniden yazılabileceğini unutmayın:

@Test(expected=IncorrectArgumentForSetter.class)
public void testSetterForeignWord("") throws Exception {
  card.setForeignWord("");
}

Ayrıca, standart Java istisnalarının kullanılmasını tercih etmelisiniz. Sizin IncorrectArgumentForSettermuhtemelen olmalıdır IllegalArgumentException.


4
Fail () yöntemi ve assertX () yöntemleri gerçekten sadece bir AssertionError atar, bu da test yönteminin kirli bir şekilde çıkmasına neden olur. Bu yüzden başarılı bir dönüş başarıyı gösterir ...
Steven Schlansker

-1 - pass () yöntemi hiçbir şey yapmıyor - istisnasız testten hemen çıkılıyor. Bu, çoğu durumda (beklenen istisnalar, zaman aşımları vb. Dışında) return ifadesine etkin bir şekilde eşdeğer olacaktır.
topchef

1
@Grigory: Bir pass()yöntemin hiçbir şey yapamayacağı konusunda haklısın , yoksa bir testin çağrıldıktan sonra başarısız olması mümkün olabilir. Ben de bu cümleyi kaldırdım.
ColinD

Yeterince teşekkür edemem, birçok hayal kırıklığından kurtulmama yardımcı oldu!
N00b Pr0grammer

71

Testiniz returnbittiğinde ve geçtiğinizde çağrı ifadesi.


3
+1 doğru cevap olmalı (çoğu durumda beklenen, zaman aşımları vb.
Hariç

Gerçekten de bir testi bitirmenin en basit ve kullanışlı yolu gibi görünüyor.
Benj

7

Bence bu sorunun güncel bir cevaba ihtiyacı var, çünkü buradaki cevapların çoğu oldukça güncel değil.

İlk olarak OP'nin sorusuna:

Bence JUnit'e "beklenen istisna" konseptini eklemenin kötü bir hareket olduğu kabul edildi, çünkü bu istisna herhangi bir yerde ortaya çıkabilir ve testi geçecektir. Çok alana özgü istisnalar atarsanız (ve iddia ederseniz) işe yarar, ancak bu tür istisnaları yalnızca kesinlikle kusursuz olması gereken kod üzerinde çalışırken atarım - çoğu APIS, IllegalArgumentExceptionveya gibi yerleşik istisnaları atar. IllegalStateException. Yaptığınız iki çağrı bu istisnaları potansiyel olarak ortaya çıkarabilirse, o zaman @ExpectedExceptionek açıklama, istisnayı fırlatan yanlış satır olsa bile testinize yeşil çubuk verecektir!

Bu durum için buradaki diğerlerinin yazdığından emin olduğum bir sınıf yazdım, bu bir assertThrowsyöntem:

public class Exceptions {
    private Exceptions(){}

    public static void assertThrows(Class<? extends Exception> expectedException, Runnable actionThatShouldThrow){
        try{
            actionThatShouldThrow.run();
            fail("expected action to throw " + expectedException.getSimpleName() + " but it did not.");
        }
        catch(Exception e){
            if ( ! expectedException.isInstance(e)) {
                throw e;
            }
        }
    }
}

bu yöntem, istisna atılırsa basitçe geri döner ve testinizde daha fazla iddia / doğrulama yapmanızı sağlar.

java 8 sözdizimi ile testiniz gerçekten güzel görünüyor. Yöntemi kullanan modelimizdeki daha basit testlerden biri aşağıdadır:

@Test
public void when_input_lower_bound_is_greater_than_upper_bound_axis_should_throw_illegal_arg() {
    //setup
    AxisRange range = new AxisRange(0,100);

    //act
    Runnable act = () -> range.setLowerBound(200);

    //assert
    assertThrows(IllegalArgumentException.class, act);
}

Bu testler biraz riskli çünkü "hareket et" adımı aslında herhangi bir eylem gerçekleştirmiyor, ancak bence anlam hala oldukça açık.

Ayrıca maven üzerinde , istisnaların atıldığını doğrulamak için sahte stil sözdizimini kullanan catch-exception adlı küçük bir kitaplık var . Güzel görünüyor, ancak dinamik vekillerin hayranı değilim. Bununla birlikte, sözdizimi o kadar zarif ki cazip kalır:

// given: an empty list
List myList = new ArrayList();

// when: we try to get the first element of the list
// then: catch the exception if any is thrown 
catchException(myList).get(1);

// then: we expect an IndexOutOfBoundsException
assert caughtException() instanceof IndexOutOfBoundsException;

Son olarak, bu konuya ulaşmak için karşılaştığım durum için, bazı koşullar karşılanırsa testleri görmezden gelmenin bir yolu var .

Şu anda JNA adlı bir java yerel kitaplık yükleme kitaplığı aracılığıyla çağrılan bazı DLL'ler almak için çalışıyorum, ancak derleme sunucumuz ubuntu'da. Bu tür bir geliştirmeyi JUnit testleri ile sürdürmeyi seviyorum - bu noktada "birimlerden" uzak olsalar bile -. Yapmak istediğim şey, yerel bir makinedeysem testi çalıştırmak, ancak ubuntu'daysak testi göz ardı etmek. JUnit 4'ün bunun için şu adı verilen bir hükmü vardır Assume:

@Test
public void when_asking_JNA_to_load_a_dll() throws URISyntaxException {
    //this line will cause the test to be branded as "ignored" when "isCircleCI" 
    //(the machine running ubuntu is running this test) is true.
    Assume.assumeFalse(BootstrappingUtilities.isCircleCI());
    //an ignored test will typically result in some qualifier being put on the results, 
    //but will also not typically prevent a green-ton most platforms. 

    //setup
    URL url = DLLTestFixture.class.getResource("USERDLL.dll");
    String path = url.toURI().getPath();
    path = path.substring(0, path.lastIndexOf("/"));

    //act
    NativeLibrary.addSearchPath("USERDLL", path);
    Object dll = Native.loadLibrary("USERDLL", NativeCallbacks.EmptyInterface.class);

    //assert
    assertThat(dll).isNotNull();
}

Dediğiniz gibi "hareket" belirli bir şey yapmaz, bu yüzden beklediğimiz çizgi olsun ya da olmasın, istisnayı tam olarak neyin attığını hala bilmiyoruz. Bu durumda, örneğin test edilmesi ve doğrulanması oldukça basittir, ancak testinizin sonucu döndürmeden önce iç içe geçmiş yöntemleri kullanan Yardımcı Program yöntemini içerdiğini düşünün. IDE istisna sitesini belirtmedikçe sorunun kaynağını
Farid

4

passJUnit için de yöntem arıyordum , böylece bazı senaryolarda uygulanamayan bazı testleri kısa devre yapabilirim (saf birim testleri yerine entegrasyon testleri vardır). Çok kötü, orada olmaması.

Neyse ki, bir testin şartlı olarak göz ardı edilmesini sağlamanın bir yolu var, ki bu assumeTrueyöntem kullanarak benim durumuma daha da iyi uyuyor :

Assume.assumeTrue (isTestApplicable);

Yani burada test yalnızca isTestApplicable doğruysa yürütülecektir, aksi takdirde test yok sayılacaktır.


2

Geçiş yöntemine gerek yoktur çünkü test kodundan AssertionFailedException atılmadığında birim test durumu geçecektir.

Fail () yöntemi, denetim bu noktaya gelirse testCase'de başarısız olmak için bir AssertionFailedException oluşturur.


Aslında bunun bir junit.framework.AssertionFailedError olduğunu düşünüyorum.
Kyle

Hata durumları ne olacak? diyorum ki, webdriver'dan görünen bir istisna değil. İstisna yakalayıp geri dönmeli miyim.
sasikumar

1

Bu sorunun test yürütme sürecinin küçük bir yanlış anlaşılmasının bir sonucu olduğunu düşünüyorum. JUnit'te (ve diğer test araçlarında) sonuçlar, onay çağrısı başına değil, yöntem başına sayılır. Kaç tane başarılı / başarısız assertXyapıldığını takip eden bir sayaç yoktur .

JUnit, her test yöntemini ayrı ayrı yürütür. Yöntem başarılı bir şekilde dönerse, test "geçti" olarak kaydedilir. Bir istisna meydana gelirse, test "başarısız" olarak kaydedilir. İkinci durumda, iki alt harf mümkündür: 1) bir JUnit ispat istisnası, 2) diğer her türlü istisna. Durum ilk durumda "başarısız" ve ikinci durumda "hata" olacaktır.

Gelen Assertsınıfının birçok stenografi yöntemleri sav istisnalar atmak için avaiable. Başka bir deyişle, AssertJUnit'in istisnalarının üzerinde bir soyutlama katmanıdır.

Örneğin, bu kaynak kodu assertEqualsüzerinde GitHub'dan :

/**
 * Asserts that two Strings are equal.
 */
static public void assertEquals(String message, String expected, String actual) {
    if (expected == null && actual == null) {
        return;
    }
    if (expected != null && expected.equals(actual)) {
        return;
    }
    String cleanMessage = message == null ? "" : message;
    throw new ComparisonFailure(cleanMessage, expected, actual);
}

Gördüğünüz gibi eşitlik durumunda hiçbir şey olmaz, aksi takdirde bir istisna atılır.

Yani:

assertEqual("Oh!", "Some string", "Another string!");

ComparisonFailureJUnit tarafından yakalanacak olan bir istisna atar ve

assertEqual("Oh?", "Same string", "Same string");

hiç birşey yapmıyor.

Özetle, böyle bir şey pass()hiçbir anlam ifade etmiyor çünkü hiçbir şey yapmıyordu.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.