首页 > 其他分享 >单元测试与Mock

单元测试与Mock

时间:2023-07-14 17:44:12浏览次数:39  
标签:PowerMockito String mock 单元测试 class Mock public 模拟

JUnit 4

以下是JUnit 4中一些常用的类和注解的相关API:

  1. 注解:
    • @Test:标记测试方法。
    • @Before:在每个测试方法之前执行的方法。
    • @After:在每个测试方法之后执行的方法。
    • @BeforeClass:在整个测试类之前执行的静态方法。
    • @AfterClass:在整个测试类之后执行的静态方法。
    • @RunWith:指定自定义的测试运行器(Runner)。
    • @Ignore:忽略某个测试方法或测试类。
  2. 断言(Assert):
    • Assert.assertEquals(expected, actual):判断两个值是否相等。
    • Assert.assertTrue(condition):判断给定条件是否为真。
    • Assert.assertFalse(condition):判断给定条件是否为假。
    • Assert.assertNull(actual):判断给定对象引用是否为空。
    • Assert.assertNotNull(actual):判断给定对象引用是否不为空。
  3. 测试运行器(Runner):
    • BlockJUnit4ClassRunner:默认的JUnit 4运行器,用于执行测试类。
    • Parameterized:用于执行参数化测试。
    • Categories:用于按照测试类或测试方法分类执行。

JUnit 5

JUnit 5JUnit 4是两个不同版本的Java单元测试框架,它们有一些区别和改进。

以下是一些主要的区别和特性:

  1. 注解方式: JUnit 4使用@Test注解来标记测试方法,而JUnit 5使用@org.junit.jupiter.api.Test注解。JUnit 5还引入了其他新的注解,如@BeforeEach@AfterEach@BeforeAll@AfterAll等,用于在测试方法执行前后进行设置和清理操作。
  2. 扩展模型: JUnit 4使用@RunWith注解来指定运行器(Runner),而JUnit 5引入了更灵活的扩展模型,并使用@ExtendWith注解来应用扩展(如Mockito、Spring等)。这使得JUnit 5更加可扩展和定制化。
  3. 参数化测试: JUnit 5引入了参数化测试的功能,可以使用@ParameterizedTest注解来定义参数化测试方法,并通过提供不同的测试参数执行多次测试。
  4. 断言方式: JUnit 4使用Assert类中的静态方法来进行断言,例如Assert.assertEquals()。JUnit 5将断言功能移到了org.junit.jupiter.api.Assertions类中,提供了更多的断言方法,例如assertAll()assertThrows()assertTimeout()等,以及优化的错误消息输出。
  5. 并发测试: JUnit 5提供了一些新的注解和工具类,用于编写并发测试。例如,@RepeatedTest注解可以重复执行测试,Assertions.assertTimeoutPreemptively()方法可以设置超时时间来进行并发测试。
  6. 动态测试: JUnit 5引入了动态测试的功能,允许在运行时生成和执行测试。这对于需要根据特定条件生成一组测试用例或在运行时确定测试参数的情况非常有用。

选择使用哪个版本取决于你的项目需求、团队偏好以及与其他框架的集成性等因素。但在JUnit 5中有很多新的功能和改进。如果你要开始一个新的项目或者对现有项目进行维护,推荐使用JUnit 5来获得更好的支持和功能。

Mockito

在Java项目中,一般的项目依赖比较多,单纯靠JUnit很难完成单元测试的编写,为了让单元测试的编写更加灵活高效,各种Mock框架应运而生,其中最为经典的非Mockito莫属。

Mockito是一个常用的Java模拟框架,用于在单元测试中创建和管理模拟对象(mocks)。下面是一些Mockito常用的API:

  1. 创建模拟对象:
    • mock(Class<T> classToMock):创建指定类或接口的模拟对象。
    • @Mock注解:在测试类中使用该注解标注字段,可以自动创建模拟对象。
  2. 设置模拟对象行为和返回值:
    • when(mock.method()).thenReturn(value):配置模拟对象方法调用时的返回值。
    • doReturn(value).when(mock).method():与上述方式功能相同,但使用不同的语法。
    • when(mock.method()).thenThrow(exception):配置模拟对象方法调用时抛出异常。
    • doThrow(exception).when(mock).method():与上述方式功能相同,但使用不同的语法。
  3. 验证模拟对象的方法调用:
    • verify(mock).method():验证模拟对象的方法是否被调用。
    • verify(mock, times(n)).method():验证模拟对象的方法被调用了指定次数。
    • verify(mock, never()).method():验证模拟对象的方法从未被调用。
    • verify(mock, atLeastOnce()).method():验证模拟对象的方法至少被调用一次。
    • verifyNoMoreInteractions(mock):验证模拟对象除了已验证的方法外没有其他交互。
  4. 模拟对象参数匹配:
    • any(Type class):匹配任意类型的参数。
    • eq(value):与指定值相等的参数。
    • anyInt()anyString()anyList()等:用于匹配特定类型的参数。
    • argThat(Matcher<T> matcher):使用自定义的参数匹配器。
  5. 重置模拟对象:
    • reset(mock):重置模拟对象的状态,清除之前的行为和交互记录。

以上只是Mockito提供的一些常用API示例,还有更多功能和方法可以根据具体测试需求进行探索和使用。在编写单元测试时,合理使用Mockito的API可以帮助你轻松创建和管理模拟对象,并进行验证和断言操作。

使用

在Maven项目中仅需要引入mockito-core的包,选择合适的版本

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>3.7.7</version>
    <scope>test</scope>
</dependency>

示例场景

在系统中一个获取所有sku信息的接口,该接口通过调用其他远程服务获取数据,如何编写单元测试验证业务代码的正确呢?

public interface MallItemApiService {

    /**
     * 获取全部的sku信息
     * @return sku信息
     */
    List<MallSkuResponse> getAllSku();
}
package com.meifute.mall.adapter.item;

import com.fasterxml.jackson.core.type.TypeReference;
import com.meifute.mall.adapter.MallSenderHelper;
import com.meifute.mall.adapter.common.ApiResult;
import com.meifute.mall.adapter.item.response.MallSkuResponse;
import com.meifute.mall.adapter.item.response.Sku;
import com.meifute.mall.adapter.util.JSONUtils;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

public class MallItemApiServiceImpl implements MallItemApiService {

    private final MallSenderHelper mallSenderHelper;

    public MallItemApiServiceImpl(MallSenderHelper mallSenderHelper) {
        this.mallSenderHelper = mallSenderHelper;
    }

    /**
     * 获取全部的sku信息
     * @return sku信息
     */
    @Override
    public List<MallSkuResponse> getAllSku() {

        //  所有商品接口
        String result = mallSenderHelper.doGet(ItemPathConstant.FIND_ALL_SKU);
        ApiResult<List<Sku>> apiResult = JSONUtils.read(result, new TypeReference<ApiResult<List<Sku>>>() {
        });
        apiResult.assertSuccess();

        return MallSkuResponse.of(apiResult.getData());
    }
}


@RunWith(MockitoJUnitRunner.class)
public class MallItemApiServiceTest {

    @Mock
    private  MallSenderHelper mallSenderHelper;

    @InjectMocks
    private MallItemApiServiceImpl mallItemApiService;

    @Before
    public void setUp() {
        mallItemApiService = new MallItemApiServiceImpl(mallSenderHelper);
    }

    @Test
    public void getAllSkuTest(){

        // 模拟接口返回的数据
        Unit unit = new Unit();
        unit.setId(1);
        unit.setName("单位");

        Sku sku = new Sku();
        sku.setCode("A0001");
        sku.setId(11L);
        sku.setPrice(BigDecimal.ZERO);
        sku.setStorageUnit(unit);
        sku.setState(GoodsState.ON);

        List<Sku> skus = Collections.singletonList(sku);
        ApiResult<List<Sku>> apiResult = new ApiResult<>();
        apiResult.setData(skus);

        // 模拟doGet方法返回的结果
        String result = JSONUtils.write(apiResult);
        when(mallSenderHelper.doGet(ItemPathConstant.FIND_ALL_SKU)).thenReturn(result);

        // 调用被测方法
        List<MallSkuResponse> response = mallItemApiService.getAllSku();

        // 验证断言
        assertEquals(1, response.size());
        assertEquals("A0001", response.get(0).getSkuCode());

        // 验证调用次数和参数
        verify(mallSenderHelper, times(1)).doGet(ItemPathConstant.FIND_ALL_SKU);
    }

}

通过上面的例子可以看出,在运行单元测试时,并没有远程的调用接口,而是Mock模拟了一个对象的行为,并进行断言验证。这里也符合单元测试仅仅验证业务代码是否正确的目的,并不需要将所有的依赖全部引入。

@mock注解

从上面的例子可以看出,被@mock修饰的变量将会产生一个mock对象,对这个生成的mock对象可以模拟它的行为。

@InjectMocks注解

使用@InjectMocks注解可以方便地自动创建被测类的实例,并自动将模拟对象注入到被测类中所需的依赖属性上。

spy

在Mockito中,spy是一种用于部分模拟(partial mocking)的功能。通过使用spy,可以创建一个真实的对象,并对其部分行为进行模拟。与mock不同,spy保留了对象的原始状态和行为,只对显式指定的方法进行模拟,而其他方法将继续执行真实的逻辑。

// 创建一个真实的对象
List<String> list = new ArrayList<>();

// 将对象转换为spy
List<String> spyList = spy(list);

// 对指定方法进行模拟
when(spyList.size()).thenReturn(10);

// 调用被测对象的方法
int size = spyList.size();  // 返回模拟的值,即10
String element = spyList.get(0);  // 执行真实的方法,返回列表中的第一个元素

// 验证模拟方法的调用次数
verify(spyList).size();

静态方法

在实际工作中,我们经常还会遇到需要对静态方法进行mock的情况,在Mockito 3.4.0前需要借助PowerMock才能实现,3.4.0后开始了对静态方法mock的支持,主要是通过mockito-inie包进行实现。

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-inline</artifactId>
    <version>3.7.7</version>
    <scope>test</scope>
</dependency>

比如想要对下面这个IpUtil的工具类进行单元测试

import java.net.InetAddress;
import java.net.UnknownHostException;

public class IpUtils {
    
    public static String getIp() {
        try {
            return InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            return null;
        }
    }
}
@RunWith(MockitoJUnitRunner.class)
public class IpUtilsTest {

    @Test
    public void getIpTest() {

        String target = "192.168.2.1";

        try (MockedStatic<IpUtils> mockStatic = Mockito.mockStatic(IpUtils.class);) {
            mockStatic.when(IpUtils::getIp).thenReturn(target);

            Assert.assertEquals(IpUtils.getIp(), target);
        }
    }
}

PowerMockito

PowerMockito是一个基于Mockito的拓展框架,他提供了更多的操作,包括对私有方法、静态方法和构造函数的模拟和验证。

虽然PowerMockito提供了更多强大的功能来进行单元测试,但也要慎重使用,避免滥用。优先考虑通过公共接口进行测试,只在必要时才使用PowerMockito来处理特定情况下的静态方法、私有方法或构造函数。

以下是一些常用的PowerMockito示例:

  1. Mock静态方法:
    • PowerMockito.mockStatic(ClassToMock.class):模拟静态类。
    • PowerMockito.when(ClassToMock.staticMethod()).thenReturn(value):配置模拟静态方法调用时的返回值。
  2. Mock私有方法:
    • ClassToMock spyObject = PowerMockito.spy(new ClassToMock()):创建目标对象的模拟实例。
    • PowerMockito.doReturn(value).when(spyObject, "privateMethod", arg1, arg2):配置模拟私有方法调用时的返回值。
  3. Mock构造函数:
    • PowerMockito.whenNew(ClassToMock.class).withArguments(args).thenReturn(mockObject):模拟构造函数的调用,并返回模拟对象。
  4. 禁用构造函数:
    • PowerMockito.suppress(PowerMockito.constructor(ClassToSuppress.class)):禁用指定类的构造函数。
  5. 验证静态方法调用:
    • PowerMockito.verifyStatic(ClassToMock.class):验证静态方法被调用。
    • PowerMockito.verifyStatic(times(n)):验证静态方法被调用n次。
  6. 验证私有方法调用:
    • PowerMockito.verifyPrivate(spyObject).invoke("privateMethodName", arg1, arg2):验证私有方法被调用。
  7. 重放所有模拟和验证:
    • PowerMockito.replayAll():重放所有模拟对象。
    • PowerMockito.verifyAll():验证所有模拟对象的方法调用。

使用

需要注意的是PowerMockito有可能会和Mockito产生冲突,需要选择合适的版本

<properties>
    <java.version>1.8</java.version>
    <powermock-version>2.0.2</powermock-version>   
    <mockito-version>2.23.4</mockito-version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-core</artifactId>
        <mockito-version>${mockito-version}</mockito-version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-api-mockito2</artifactId>
        <version>${powermock-version}</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-module-junit4</artifactId>
        <version>${powermock-version}</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-core</artifactId>
        <version>${powermock-version}</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-module-junit4-rule</artifactId>
        <version>${powermock-version}</version>
        <scope>test</scope>
    </dependency> 
</dependencies>

示例场景

如果想要使用PowerMockitoUserManager进行单元测试,代码如下所示:

public final class UserManager {

    private final UserService service;

    public UserManager(UserServiceImpl service) {
        this.service = service;
    }

    public User saveUser(User user) {
        User save = service.save(user);
        return save;
    }

    public String returnName(){
       return getStaticName("ljw1") + " aaa";
    }

    public String httpReturnName(HttpServletRequest request){
        return httpGetStaticName("ljw1", request) + " aaa";
    }

    public static String getStaticName(String name) {
        return "A_" + name;
    }

    public static String httpGetStaticName(String name, HttpServletRequest request) {
        String aaa = request.getParameter("aaa");
        return aaa + "A_" + name;
    } 

    public String getPrivateName(String name) {

        if (publicCheck()){
            return "public 被mock 了";
        }
        if (check(name)){
            return "private 被mock 了";
        }
        return "A_" + name;
    }

    public boolean publicCheck() {
        return false;
    }

    private boolean check(String name) {
        return false;
    }

    private String say(String content) {
        return "ljw say " + content;
    }
}

@RunWith(PowerMockRunner.class)
@PrepareForTest(UserManager.class)
public class UserManagerTest {
    @Mock
    private UserServiceImpl serviceImpl;

    @InjectMocks
    private UserManager userManager;

    /**
     * mock service的保存方法
     */
    @Test
    public void mockSave() {
        User user1 = new User();
        User user2 = new User();
        user1.setId("1");
        user2.setId("2");
        Mockito.when(serviceImpl.save(user1)).thenReturn(user2); //当调用service的save()时,mock让他返回user2
        User saveUser = userManager.saveUser(user1); //调用
        Mockito.verify(serviceImpl,Mockito.times(1)).save(user1);//verify验证mock次数
        assertEquals(user2, saveUser);//断言是否mock返回的是user2
    }

    /**
     * mock spy public Check方法
     * @throws Exception xx
     */
    @Test
    public void getPrivateNameOfPublicCheckTest() throws Exception {
        UseruserManager spy = PowerMockito.spy(userManager); //监视userManager的publicCheck方法,让他返回true
        Mockito.when(spy.publicCheck()).thenReturn(true);
        String name = spy.getPrivateName("ljw");//执行该方法
        assertEquals("public 被mock 了", name);//验证
    }

    /**
     * mock私有 check 方法
     * @throws Exception xx
     */
    @Test
    public void getPrivateNameOfPrivateCheckTest() throws Exception {
        UseruserManager spy = PowerMockito.spy(userManager);
        PowerMockito.when(spy, "check", any()).thenReturn(true);//私有方法mockito不行了,需要用PowerMock监视spy
        String name = spy.getPrivateName("ljw");
        assertEquals("private 被mock 了", name);
    }

    /**
     * mock 静态方法
     */
    @Test
    public void mockStaticMethod() {
        PowerMockito.mockStatic(UseruserManager.class);//mock静态方法
        when(UseruserManager.getStaticName(any())).thenReturn("hi");
        String staticName = UseruserManager.getStaticName("ljw");//执行
        assertEquals("hi", staticName);//验证
    }

    @Test
    public void mockStaticMethod_2() {
        PowerMockito.mockStatic(UseruserManager.class);
        when(UseruserManager.getStaticName(any())).thenReturn("hi");
        String staticName = userManager.returnName();//通过returnName()调用,看能否被mock
        assertEquals("hi", staticName);
    }

    /**
     * 静态方法传入一个HttpServerletRequest参数 + 普通方法
     * A(T.class)检查参数T的实例instance,表示它为非null。
     * same(obj)检查参数是否与obj相同,从而arg == obj为true。
     * eq(obj)根据其equals方法检查参数是否等于obj。
     * 如果在不使用匹配器的情况下传递实数值,这也是行为。
     */
    @Test
    public void mockStaticMethod_3() {
        PowerMockito.mockStatic(UseruserManager.class);
        PowerMockito.when(UseruserManager.httpGetStaticName(any(),any())).thenReturn("hi");
        String staticName = userManager.httpReturnName(eq(any()));    //通过returnName()调用,看能否被mock
        assertEquals("hi aaa", staticName);
    }

    /**
     * 测试私有方法一
     * @throws InvocationTargetException xx
     * @throws IllegalAccessException xx
     */
    @Test
    public void testPrivateMethod() throws InvocationTargetException, IllegalAccessException {
        Method method = PowerMockito.method(UseruserManager.class, "say", String.class);
        Object say = method.invoke(userManager, "hi");
        assertEquals("ljw say hi", say);
    }

    /**
     * 测试私有方法二
     * @throws Exception xx
     */
    @Test
    public void testPrivateMethod_2() throws Exception {
        Object say = Whitebox.invokeMethod(userManager, "say", "hi");
        assertEquals("ljw say hi", say);
    }

}

@PrepareForTest

在使用PowerMockito时,为了能够正确地模拟和验证目标类的静态方法、私有方法或构造函数,你需要在测试类上使用@PrepareForTest注解,并指定需要进行操作的类。@PrepareForTest注解告诉PowerMockito需要对指定类进行字节码操作,以便能够模拟和验证该类的静态方法、私有方法或构造函数。

SpringBoot

在SpringBoot项目中,只需要引入spring-boot-starter-test包,其会带入junitmockito-corespring-test包,如果需要对私有方法进行mock,需要额外引入PowerMock

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

spring-boot-test包中对Mock框架进行了一些封装,方便在单元测试和集成测试中使用,总的来说@MockBean@SpyBean主要用在集成测试阶段,但有的时候。

@MockBean

@MockBean@Mock是两个不同的注解,用于在测试中创建模拟对象(mock)。

  1. 作用范围:
    • @MockBean是Spring Boot Test框架提供的注解,用于集成测试中创建模拟对象并将其注入到Spring容器中。
    • @Mock是Mockito框架提供的注解,主要用于独立的单元测试中创建模拟对象。
  2. 依赖关系:
    • @MockBean通常与Spring Boot Test一起使用,它基于Spring应用程序上下文创建和管理模拟对象。它可以与其他Spring功能(如自动装配)无缝集成。
    • @Mock则与Mockito框架一起使用,它是一个独立的Java模拟框架,专注于模拟和验证对象的行为。
  3. 目标对象:
    • @MockBean适用于模拟Spring Bean组件,例如模拟数据库访问、外部服务调用等。
    • @Mock可以用于模拟任何类或接口的实例,不限于Spring Bean组件。
  4. 测试环境:
    • @MockBean通常用于集成测试,需要启动整个Spring应用程序上下文以便正确创建和管理模拟对象。
    • @Mock主要用于独立的单元测试,没有Spring上下文的依赖,可以更轻量地创建和使用模拟对象。

@SpyBean

Mockito中的spy类似,@SpyBean会保留原始对象的状态和行为,并只对你显式指定的方法进行模拟。这使得你可以在集成测试中针对真实的Spring组件进行测试,并对其中的部分方法进行模拟和验证。

标签:PowerMockito,String,mock,单元测试,class,Mock,public,模拟
From: https://www.cnblogs.com/wrxiang/p/17554614.html

相关文章

  • java单元测试入参数不同出参不同怎么做
    项目方案-Java单元测试入参不同出参不同的处理背景和问题在软件开发过程中,我们经常需要编写单元测试来保证代码的正确性。但是,在某些情况下,相同的测试方法可能会根据不同的输入参数而产生不同的输出结果。这给单元测试的编写带来了一定的挑战,因为我们需要针对不同的参数情况编......
  • 对一个已有项目搭建单元测试集的一个方法
    对一个已有项目搭建单元测试集的一个方法0说明1准备1.1软件环境googletestcmake1.2需要的知识单元测试相关概念1.3一般原则每次只测试一个对象,被测对象应该尽可能的独立,应该是一个很小的单元,依赖项通过mock或stub模拟;每个测试项均应执行迅速且独立于测试环境;各......
  • mock延迟响应的接口
    在使用mocoAPI做接口模拟的过程中,遇到一个模拟接口响应时间的问题。有些情况下是需要进行延迟响应的,比如我想mock一个响应时间超过5s的接口,以观察端上会如何处理这种情况。mocoAPI本身是提供一个延迟的API,但是经过尝试之后发现,这个API只是用来异步请求接口的,并不能支持延迟响应......
  • 单元测试(三)
    本篇主要介绍PowerMock+Spring+Mybatis+H2单元测试,接上篇:https://www.cnblogs.com/javaXRG/p/17538157.html1PowerMock1.1Mockito的不足不支持局部变量不支持mock静态方法不支持mockfinal修饰的类或方法不支持mock私有方法1.2PowerMock局部变量1packageor......
  • 单元测试(二)
    本节主要介绍Mockito,接上篇:https://www.cnblogs.com/javaXRG/p/17537364.html1、基础用法1.1工程代码1packageorg.example.Domain;23importlombok.AllArgsConstructor;4importlombok.Data;56@Data7@AllArgsConstructor8publicclassUser{91......
  • 单元测试 - Moq
    测试方法//准备MockIFoo接口varmock=newMock<IFoo>();//配置准备模拟的方法,当调用接口中的DoSomething方法,并传递参数"bing"的时候,返回truemock.Setup(foo=>foo.DoSomething("ping")).Returns(true);//方法的参数中使用了out参数//outargumentsvarou......
  • 软件测试常用工具总结(测试管理、单元测试、接口测试、自动化测试、性能测试、负载测试
    在软件测试的过程中,多多少少都是会接触到一些测试工具,作为辅助测试用的,以提高测试工作的效率,使用好了测试工具,能对测试起到一个很好的作用,同时,有些公司,也会要求掌握一些测试工具,或者,是在面试时,也会被问到测试工具的,比如,在面试时,最常见的问题便是,你在测试时,用的是什么测试工具?或者......
  • 单元测试-异常测试
    前面的文章(Java中的单元测试)已经说过单元测试中的mock测试,大都是正常分支下的测试,异常测试用于测试某些场景下是否会触发指定的异常,用来验证代码逻辑的正确性。目前根据Junit的版本有三种不同的方式,如下:1、@Test注解中的expected属性此方式比较简单,但是存在局限性,就是只能判断异......
  • C#中各单元测试框架比对
    下面是关于NUnit、xUnit.net、MSTest、SpecFlow和FluentAssertions等单元测试框架的优势和适用场景的简要比较:NUnit框架:优势:NUnit是一个历史悠久且成熟的框架,提供了广泛的功能和灵活性。它具有强大的断言库、丰富的扩展插件和广泛的社区支持。劣势:对初学者来说,可能存在一些学习曲线......
  • 前端文件流下载--mockjs污染全局问题
    参考文章https://blog.csdn.net/daotian2016/article/details/123670179 项目场景:项目场景:VUE工程,做了一个代码自动生成可以导出zip的功能。问题描述导出的zip文件打开提示“不可预料的压缩文件末端”,文件打不开。 exportfunctiondownLoadZip(str,filename){ varurl=......